如何写出高质量的C代码?快来学习这些coding技巧

简介: 如何写出高质量的C代码?快来学习这些coding技巧

前言

世界上有两种程序员:一种是草草写完代码然后化身苦逼程序猿苦苦寻找bug;另一种是上手就写出高质量的代码化身bug终结者。优秀的程序员往往将bug扼杀在萌芽中,很明显这是“另一种”程序猿,那么我们应该怎样写出一手高质量的优秀代码呢?

一、优秀的代码

什么是优秀的代码?优秀的代码具有以下特点:

  1. 代码运行正常
  2. bug很少
  3. 效率高
  4. 可读性高
  5. 可维护性高
  6. 注释清晰
  7. 文档齐全

二、常见coding技巧

当然了,想要写出以上优秀的代码,需要我们在编码时刻意的去使用一些编码技巧,例如一些常见的coding技巧:

  1. 使用assert
  2. 尽量使用const
  3. 养成良好的编码风格
  4. 添加必要的注释
  5. 避免编码的陷阱

现在大家可能还体会不到这些coding技巧带来的实际意义,下面就以实例向大家演示:

三、模拟实现库函数:strcpy

我们已知库函数strcpy的作用是将含有'\0'结束符的字符串复制到另一个地址空间。根据它的功能,我们利用指针偏移模拟复刻出以下代码:

虽然上述代码也可以模拟实现出strcpy函数的功能,但是这是一种非常不好的代码风格。我们应该怎样对其优化呢?

1、优化一:字符复制和‘\0’复制的整合

初代代码,我们将内容复制和最后‘\0’的复制功能分离,对此我们可以将二者功能整合,使代码更巧妙紧凑。

2、优化二:使用assert

在拷贝函数中我们对指针进行了解引用等相关操作,但是如果在传参过程中不小心传入了一个空指针呢?我们知道空指针是不能进行这些操作的,一但传入空指针该程序就会崩掉,并且我们不知所以然,还要通过调试一步一步的去定位错误。为了能够很好的预防和避免以上问题,我们可以在程序中添加assert函数:

这里我们假设无意中传入一个空指针,看看会出现什么效果:

屏幕上输出:Assertion failed:src-断言错误: src,我们可以根据提示,追根溯源一步步锁定错误。

同样都是判断,为什么不使用if语句呢?

if语句在Debug版本和Release版本都会被执行,而assert仅在Debug版本中执行,在Release版本中会被优化掉。综上来看,assert是对程序员非常友好的一个库函数。

3、优化三:const修饰

观察库函数的特征,函数中存在一个const修饰的指针变量,这里的const又有什么样的作用呢?下面我们通过以下三种代码的可执行情况来分析:

const修饰指针变量的时候:

  1. const如果放在*的左边,修饰的是指针指向的内容,保证指针指向的内容不能通过指针来改 变。但是指针变量本身的内容可变。
  2. const如果放在*的右边,修饰的是指针变量本身,保证了指针变量的内容不能修改,但是指 针指向的内容,可以通过指针改变。

结合const修饰指针变量的作用,我们对原始数据的指针变量使用const修饰,意味着原始数据不可修改,这里起到了保护原始数据的作用。

例如:在拷贝数据时我们不小心将*dest++=*src++误写成*src++=*dest++,如果不使用const修饰src,当程序报错后还需一步一步调试从而定位错误,如果使用了const修饰src,我们可以很快在报错信息中定位错误,提高效率。

4、优化四:添加返回值

字符串拷贝函数返回的是目标空间的起始地址。

5、优化五:添加注释

虽然注释并不参与编译,但是在开发中注释也具有十分重要的作用。

  1. 有助于理解
  2. 帮助修补程序或快速修复
  3. 有助于加快开发过程
  4. 有助于提高协作效率
//模拟strcpy函数--注释

//功能:
//char* my_strcpy(char* dest, const char* src)-将字符串src复制到另一个字符串dest上
//参数:
//char* dest - 目标字符串
//const char* src - 要在“dest”上复制的字符串
//返回值:
//目标字符串的首元素地址

6、最终代码

//模拟strcpy函数--注释

//功能:
//char* my_strcpy(char* dest, const char* src)-将字符串src复制到另一个字符串dest上
//参数:
//char* dest - 目标字符串
//const char* src - 要在“dest”上复制的字符串
//返回值:
//目标字符串的首元素地址

#include<assert.h>
char* my_strcpy(char* dest, const char* src)
{
  assert(dest);
  assert(src);
  char* ret = dest;//用来定位首元素地址

  while (*dest++ = *src++)//既拷贝了内容又能很好的停下
  {
    ;
  }
  return ret;
}

7、练习:模拟实现strlen函数

仿照以上优化思路,我们也可以类似的对库函数strlen进行模拟实现。

//模拟strlen函数--注释
//功能:统计字符串长度,不包括‘\0’
//参数:const char* str-被统计字符串地址
//返回值:字符串长度,不包括‘\0’

#include<assert.h>
int my_strlen(const char* str)
{
  assert(str);
  int count = 0;
  while (*str)
  {
    count++;
    str++;
  }
  return count;
}

总结

纸上得来终觉浅,绝知此事要躬行。想要写出优秀的代码,需要我们在编码时刻意的对代码进行研判,学习借鉴好的代码风格,时常总结,积累经验。在这里特别推荐两本可以提高代码质量的书籍:《高质量的C-C++编程》《C陷阱与缺陷》或许在这里面可以找到你想要的更多答案!


相关文章
|
3月前
|
存储 定位技术 API
C语言实战 -- 经典贪吃蛇游戏(含完整源码)
C语言实战 -- 经典贪吃蛇游戏(含完整源码)
73 1
|
3月前
|
C语言
|
4月前
|
存储 开发工具 文件存储
Python的核心知识点整理大全66(已完结撒花)
Python的核心知识点整理大全66(已完结撒花)
94 4
这几道Python“基础”题,竟只有20%的人答对,几乎每个人都踩过其中的坑
当你学习了Python语法基础,开始尝试开发具备完整功能的代码时,必然会遇上一些Python的语言特性。这些特性,如果你没有专门了解过,亲自在代码里测试过,那么在刚开始使用时一定会遇上或大或小的麻烦。
【C语言】手把手带你实现《完整版扫雷》
前言 这种小游戏主要锻炼我们模块化编程能力,什么是模块化编程呢 模块化编程:模块化编程就是把我们的一整个项目,分成很多模块(比如我们生产汽车,可以分为生产发动机、生产轮胎、生产车架、组装等)而一个程序工程包含多个源文件(.c 文件和 .h 文件),每个 .c 文件可以被称为一个模块,每一个模块都有其各自的功能,而每一个.h文件则是声明该模块,相当于功能说明书 ,大大提高代码可阅读性,不会使代码显得臃肿。 扫雷(游戏规则) 挖到地雷,游戏结束,挖到空方快,游戏继续,挖到数字则表示在其周围的八个方块中有多少个雷,如果怀疑一个地方是雷,可以对其进行标记,标记后的位置需要取消标记才能挖开,以免误操
|
缓存 Python
听说90%的人都答不对这道Python题
每种编程语言都有一些不为人知的陷阱,有些实际工作中会踩到,有些可能根本排不上用场,但弄明白这些陷阱有利于我们更好的去了解这门语言的实现机制。
44 0
|
存储 Java 编译器
【python】考前复习,python基础语法知识点整理(下)
变量就是用来保存数据的,如果一个数据我们要经常用到,创建一个变量把这个数据保存起来,在后面使用的时候就会很方便.
|
Java 编译器 Python
【python】考前复习,python基础语法知识点整理(上)
变量就是用来保存数据的,如果一个数据我们要经常用到,创建一个变量把这个数据保存起来,在后面使用的时候就会很方便.
|
存储 算法 Python
Python蓝桥杯易错点整理和心得总结【一】
Python蓝桥杯易错点整理和心得总结【一】
303 0
Python蓝桥杯易错点整理和心得总结【一】
|
C语言 C++
我用c语言把何同学的代码跑起来了
我用c语言把何同学的代码跑起来了
197 0
我用c语言把何同学的代码跑起来了

相关实验场景

更多