90%的C程序员都踩过这些坑,第5个连老手都翻车

发布时间:2026/7/23 4:36:39
90%的C程序员都踩过这些坑,第5个连老手都翻车 90%的C程序员都踩过这些坑第5个连老手都翻车你有没有过这种经历代码编译通过没有一行报错运行结果却完全不对。你反复检查逻辑最后发现——问题出在一个你压根没注意到的陷阱上。C语言就是这样。它给你最大的自由也给你最多的坑。编译器不会帮你拦住大部分错误它只管语法对不对不管逻辑对不对。今天盘了8个最容易踩的坑每个都附错误代码和正确写法。不管你是刚入门还是写了几年看完至少能少掉一半头发。坑1一个等号让整个循环变成死循环错误写法把写成了// 这行代码不会报任何错if(a5){printf(a等于5\n);}a 5是赋值赋值表达式的值就是 55 非零条件永远为真。写在while里恭喜死循环。正确写法常量放左边语法级防错if(a5){printf(a等于5\n);}// 更好的写法把常量写左边if(5a){// 万一少写一个等号 → 编译器直接报错printf(a等于5\n);}老手的习惯if (5 a)而不是if (a 5)。这样万一漏写一个等号变成if (5 a)编译器直接报不能给常量赋值。坑2数组越界——C语言不会拦你但内存会记仇错误写法循环条件用了intarr[5]{1,2,3,4,5};for(inti0;i5;i){printf(%d ,arr[i]);// arr[5] 越界了}C 语言不做任何数组边界检查。arr[5]访问的是数组后面的未知内存轻则打印乱码重则修改函数返回地址程序直接崩溃。更可怕的是有时候越界访问不报错数据悄悄被改了等你排查的时候已经面目全非。正确写法用而不是for(inti0;i5;i){printf(%d ,arr[i]);}记住数组长度是 N下标范围是0 ~ N-1循环条件永远是i N。坑3野指针——free之后别再碰它错误写法释放后继续使用int*p(int*)malloc(sizeof(int));*p10;free(p);*p20;// 野指针这块内存已经不属于你了free(p)之后p 指向的内存已经被系统回收。你再去读写就是进了别人家翻东西——行为完全未定义。可能崩溃可能数据错乱也可能看起来正常埋下定时炸弹。正确写法释放后立刻置空free(p);pNULL;// 置空后即使误用也会直接报错而不是偷偷搞事铁律free之后立刻p NULL这个习惯能救你无数次。坑4字符串那个看不见的 \0坑了无数人错误写法数组只留了5字节charstr[5];strcpy(str,hello);// 溢出hello看起来是 5 个字符但在 C 语言里字符串必须以\0结尾实际占6 字节。溢出的那个\0会覆盖相邻内存这就是经典的缓冲区溢出漏洞——大量安全攻击的根源。正确写法预留结束符的位置// 方法一数组多开1字节charstr[6];strcpy(str,hello);// 方法二用 strncpy 更安全charstr[6];strncpy(str,hello,sizeof(str)-1);str[sizeof(str)-1]\0;记住字符串永远多留 1 字节给\0这是 C 语言字符串处理的底线。坑5switch没写break老手也翻车错误写法每个 case 都没写 breakswitch(color){caseRED:printf(红色\n);caseGREEN:printf(绿色\n);caseBLUE:printf(蓝色\n);}如果color是RED输出会是红色、绿色、蓝色全部打印。因为 C 语言的switch是穿透的不写break就会一直往下执行。这个坑连写了好几年的老手偶尔也会踩到尤其是加班到凌晨的时候。正确写法每个 case 都加 breakswitch(color){caseRED:printf(红色\n);break;caseGREEN:printf(绿色\n);break;caseBLUE:printf(蓝色\n);break;}例外情况有时候穿透是故意的比如多个 case 共用一段逻辑但必须加注释说明否则后人会以为是 bug。坑6sizeof对指针和数组结果完全不同错误写法在函数里用 sizeof 求数组长度voidprint_arr(intarr[]){intlensizeof(arr)/sizeof(arr[0]);// 错误结果不是你想要的}数组作为函数参数时会退化为指针。sizeof(arr)在函数内部得到的是指针的大小4 或 8 字节不是数组的总大小。这个坑非常隐蔽编译不报错只是算出来的长度完全不对。正确写法数组长度必须在传参时一并传入voidprint_arr(intarr[],intlen){for(inti0;ilen;i){printf(%d ,arr[i]);}}// 调用时intdata[]{1,2,3,4,5};intlensizeof(data)/sizeof(data[0]);// 这里算才是对的print_arr(data,len);记住数组传参 传指针。想知道长度必须显式传入。坑7malloc不检查返回值等于给自己埋雷错误写法不检查 malloc 是否成功int*p(int*)malloc(1000000000*sizeof(int));*p10;// 如果 malloc 失败返回 NULL直接崩溃当内存分配失败时malloc返回NULL。如果你不检查就解引用就是空指针访问程序直接段错误。这种 bug 在开发环境内存充足下很难复现到了生产环境才爆——最难查的那种。正确写法每次 malloc 都检查返回值int*p(int*)malloc(1000000000*sizeof(int));if(pNULL){perror(内存分配失败);return-1;}*p10;铁律malloc之后必须先检查NULL再使用。没有例外。坑8运算符优先级——你以为的顺序不是实际的顺序错误写法想判断 flag 的某一位是否为 1if(flagsFLAG!0)// 实际执行的是 flags (FLAG ! 0)!的优先级高于所以实际先算FLAG ! 0结果为 1再用flags 1。和你的本意完全不同。C 语言有15 个优先级层次没人能全记住。正确写法加括号别指望记忆if((flagsFLAG)!0)原则遇到位运算、逻辑运算混合的表达式永远加括号。这不是水平问题是态度问题。写在最后C 语言的坑远不止这 8 个但这 8 个是最常踩的。它们的共同特点是编译不报错运行可能不报错但结果一定不对。记住几条铁律赋值和比较分开常量放左边数组循环用别用free之后立刻NULL字符串永远多留 1 字节switch每个case都加break数组传参必须带长度malloc必须检查返回值位运算加括号别背优先级C语言不会保护你但你可以保护自己。