返回列表 发新帖我要提问本帖赏金: 20.00元(功能说明)

[麦麦茶水间] 【每周分享】C语言中容易发生的几个常见错误

[复制链接]
30200|11
 楼主| dffzh 发表于 2025-8-8 13:22 | 显示全部楼层 |阅读模式
本帖最后由 dffzh 于 2025-8-8 13:26 编辑

#申请原创#
@21小跑堂


在基于C语言的嵌入式产品开发中,我们会经常解决和修复一些Bug,甚至有时候会被疑难杂症整的脑壳疼,以为是什么高深莫测的问题,但是呢,有时候一些Bug分析到最后,一般都是由一些小问题导致的,这些小问题包括数据溢出,数组越界和指针未初始化等等,所以我就根据自己的一些经验和遇到的,讲解在C语言开发中比较容易发生的几个错误,包括错误产生的原因,举例说明及如何规避。
1. 忽略程序编译警告
在程序编译时,更多时候我们可能只关注错误errors,而容易忽略警告warnnings,哪怕警告有几十甚至上百个。其实,很多警告就是在提醒我们该处代码操作存在潜在问题,在特定情况下可能会造成程序错误。比如下面这个就是一个比较常见的警告信息:

大概意思就是此处应该用定义的枚举数据,但实际上用的可能是整型等数据类型。
如果你用的非枚举数据值是在已定义的枚举数据里面,是没有问题的,如果你用的值不在这个里面,你的程序会怎么执行?你有做入参检查吗?因此,对应这个警告,你就尽可能的直接使用枚举数据来调用,这肯定就不会错了,其实这个也算是编程习惯问题。类似的还有:


因此在程序开发时,尽量做到下面这样就完美了,可以帮你提前规避一些程序潜在问题:


2. 宏定义漏掉括号
我们使用#define定义宏时,除非必须要加括号才加,有时候我们可能不会刻意加上括号,也可能是忘记加了,结果程序运行出现异常,反查代码后才发现原来是漏掉括号导致的。比如下面的代码就是很经典的一个案例,目的是求x的平方值:
  1. #define SQUARE(x) x*x
  2. unsigned char a=1;
  3. printf("%d\r\n", SQUARE(a+1));
我们的想法肯定是求(a+1)*(a+1)=4,但实际结果为什么是3呢?

因为宏定义漏掉了括号,导致程序实际执行的是a+1*a+1=3;
因此最好的定义方式是:
  1. #define SQUARE(x) ((x)*(x))
即使用#define定义宏时,对每一个最小单位的操作数都加上括号,哪怕就一个数字也加上,养成良好的习惯:
  1. #define MAX (255)

3. 变量没有执行初始化操作
对于全局变量和局部变量,特别是局部变量,我们一定要加初始化操作,即声明好一个变量后,先完成对其的初始化操作。对于局部变量,如果不进行初始化,其默认值不一定是0,可能是其他的随机值,容易导致难以预测的结果,我们来看看下面的代码执行结果就知道了:


4. 使用==等号判断浮点数是否相等
因为浮点数在不同系统上呈现出来的精度是不一样的,我们不能像整型数据那样用==等号来判断两个浮点数是否相等,这样会导致比较结果错误,影响程序的运行逻辑,即不能按如下代码操作:
  1. float a = 0.11;
  2. float b = 0.11;
  3. if (a == b)
  4. {
  5.     printf("Equal\n");
  6. } else
  7. {
  8.     printf("Not Equal\n");
  9. }
而应该使用一个比较小的阈值THRESHOLD来间接判断两个浮点数是否相等,即按如下代码操作:
  1. #define THRESHOLD (0.000001)  //该值视系统和具体情况进行自定义修改
  2. float a = 0.11;
  3. float b = 0.11;
  4. if (fabs(a - b) < THRESHOLD)
  5. {
  6.     printf("Equal\n");
  7. } else
  8. {
  9.     printf("Not Equal\n");
  10. }

5. 使用数组对字符串的处理不正确
因为字符串用数组定义的话,是属于字符数组,我们很容易忽视结束符“\0”,从而导致访问越界,比如下面的代码编译时就直接报错了:

因为hello加上\0是6个字符,而数组大小是5,因此错误了。对于这种情况,可以用:
  1. char str[6] = "hello";  //在数组中具体指明长度
对应字符串较长的情况,我们总不能一个一个去数吧,那就可以按如下方式定义:
  1. char str[] = "hello, my name is C program!";  //数组长度空,在C语言中是允许的

6. 数组越界操作
数组是我们经常会使用到的一种数据结构,也是很容易出错的,主要原因是数组里定义的元素总数假设为MAX,此时我们实际可以访问的数组元素是从数组[0]~数组[MAX-1],而并非是数组[MAX],如果你误操作用上数组[MAX],就属于数组越界操作了,可能会导致程序崩溃等,如下代码即为越界操作的示例:
因此,对于数组操作,我们尽量定义一个数组长度的宏,通过使用这个宏可以规避不少误操作:
  1. #define  ARRAY_LENGTH_MAX  (5)
  2. int i=0;
  3. int arr[ARRAY_LENGTH_MAX] = {1, 2, 3, 4, 5};
  4. printf("%d\n", arr[ARRAY_LENGTH_MAX-1]);
  5. for(i=0; i<ARRAY_LENGTH_MAX; i++)
  6. {
  7.         printf("%d\n", arr[i]);
  8. }
以上通过实际代码讲解了C语言开发中经常遇见的几个错误以及如何规避和预防。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?注册

×

打赏榜单

21小跑堂 打赏了 20.00 元 2025-09-15
理由:恭喜通过原创审核!期待您更多的原创作品~~

评论

介绍C语言开发时常见的一些错误,举例说明,加强**。  发表于 2025-9-15 17:39
@21小跑堂 管理员,你好,求原创审核哦!  发表于 2025-8-8 13:28
wahahaheihei 发表于 2025-8-27 19:55 | 显示全部楼层
还是要细心。
wahahaheihei 发表于 2025-8-27 19:55 | 显示全部楼层
设计程序的时候要细心,另外要考虑是否以后修改,修改的就要定义宏,方便修改。

评论

是的,考虑以后的可维修性。  发表于 2025-8-28 08:44
小岛西岸来信 发表于 2025-9-4 14:08 | 显示全部楼层
数组越界:未检查下标范围,访问超出数组定义的元素,导致内存混乱。
指针错误:使用未初始化、空指针或野指针,或指针操作后未释放内存,引发崩溃或内存泄漏。
类型不匹配:如整型与浮点型混用、不同长度变量赋值,导致计算错误或数据截断。
内存泄漏:动态分配内存(如malloc)后未free,长期运行会耗尽内存。
逻辑错误:如循环条件写错致死循环、分支判断遗漏边界值,程序逻辑偏离预期。

评论

总结到位。  发表于 2025-9-12 10:13
毛雪121225 发表于 2025-9-11 17:42 | 显示全部楼层
调试程序时候绝对不能留尾巴,要一次性消除所有潜在问题。

评论

想法是很好的,但是又有多少人真正能够完全做到,很难。  发表于 2025-9-12 10:14
毛雪121225 发表于 2025-9-12 10:57 | 显示全部楼层
那倒是,这种严谨的态度不是一天半天养成的

评论

是的,主要是需要养成好的编码习惯。  发表于 2025-9-12 11:10
您需要登录后才可以回帖 登录 | 注册

本版积分规则

175

主题

1581

帖子

23

粉丝
快速回复 在线客服 返回列表 返回顶部