news 2026/4/23 6:44:08

【每周分享】C语言中容易发生的几个常见错误

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
【每周分享】C语言中容易发生的几个常见错误

在基于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语言开发中经常遇见的几个错误以及如何规避和预防。


---------------------
作者:dffzh
链接:https://bbs.21ic.com/icview-3477780-1-1.html?_dsign=bfdf001b
来源:21ic.com
此文章已获得原创/原创奖标签,著作权归21ic所有,任何人未经允许禁止转载。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/23 6:33:22

DeOldify批量任务队列:Celery异步处理+Redis消息队列集成教程

DeOldify批量任务队列&#xff1a;Celery异步处理Redis消息队列集成教程 1. 项目概述与需求分析 1.1 为什么需要批量处理 在实际的图像上色应用场景中&#xff0c;我们经常需要处理大量图片&#xff1a; 老照片数字化修复项目&#xff0c;一次处理数百张家庭老照片影视制作…

作者头像 李华
网站建设 2026/4/23 6:25:50

教育领域的变革:个性化 AI 导师 Agent

教育领域的变革:个性化 AI 导师 Agent 1. 引入与连接(唤起兴趣与建立关联) 1.1 引人入胜的开场:一场跨越时空的课堂对话 1925年,苏联教育心理学家维果茨基(Lev Vygotsky)坐在莫斯科国立大学的教室里,对着一群未来的教育者写下了《教育心理学》手稿中的那句核心论断—…

作者头像 李华
网站建设 2026/4/23 6:23:28

别再傻傻分不清了!MATLAB矩阵运算的点乘(.*)和矩阵乘(*)到底啥区别?

MATLAB矩阵运算深度解析&#xff1a;元素级操作与矩阵级操作的本质差异 引言&#xff1a;为什么我们需要区分这两种运算&#xff1f; 在MATLAB的世界里&#xff0c;矩阵运算就像是一把瑞士军刀&#xff0c;功能强大但需要正确使用。许多初学者在使用MATLAB进行科学计算或工程仿…

作者头像 李华