c语言三位数陷阱,C语言陷阱---丢三落四

"本文针对C语言初学者常犯的错误进行了详细分析,包括: scanf 使用时忘记取地址符导致运行时错误,switch 语句中 case 分支缺少 break 导致逻辑错误,动态内存分配忽视字符串结束符 '',以及循环条件错误引发的数组越界问题。这些错误往往在编译时不易察觉,但在运行时可能导致程序崩溃或逻辑混乱。提醒程序员在编程时保持严谨,避免这类低级错误。"
摘要由CSDN通过智能技术生成

引言

对于 C 语言初学者而言,丢三落四的毛病比较严重,而某些错误,编译器也不会给出任何错误或警告的提示,以致于当程序编译通过而能运行时,浑然不知自己已经掉入了 C 的陷阱中。

注:本文如无特别说明,示范代码均在 Win7 64位英文系统, Dev-C++  4.9 环境下编译执行。

接收标准输入时普通变量缺少取地址&符号

1. 示范代码

#include

int main()

{

int a;

printf("Input an integer: ");

scanf("%d", a); /* 缺少取址符号 & */

printf("a = %d\r\n", a);

return 0;

}

2. 错误分析

示范代码能够编译通过且能“正常”运行,但是当输入一个整数时,会出现运行时错误而导致程序崩溃。

问题的关键在于 scanf 函数接收标准输入时,接收输入值的参数必须为某个地址。由于代码声明整型变量 a 且没有初始化,a 的值是随机的。当用户输入值后,会将值保存到变量 a 的值所在地址中,该值由于随机性,往往是非法的地址,所以导致程序发送运行时错误而崩溃。

使用switch语句时case分支缺少break语句

1. 示范代码

#include

int main()

{

char a;

printf("Please input a score rank from list (A, B, C, D): ");

scanf("%c", &a);

switch(a)

{

case 'A':

printf("Excellent!\n");

break;

case 'B':

printf("Well Done!\n"); /* 缺少 break 语句?*/

case 'C':

printf("Good!\n");

break;

case 'D':

printf("You should work hard!\n");

break;

default:

printf("Unknown rank: %c", a);

}

}

2. 错误分析

以上示范代码,当输入除 ”B“以外的字符时,都能按照原意运行。但是当输入”B“时,输出结果变成了如下所示:

Please input a score rank from list (A, B, C, D): B

Well Done!

Good!

该问题就在于在判断 ‘B’ 的 case分支中,缺少了 break 语句,导致执行完该分支后,继续往下执行,直到在 ‘C’的case分支中遇到 break 语句才终止。该示范代码比较简单,估计不太容易犯这种低级错误。但是当case分支很多,而且每个分支的代码比较复杂时(分支太复杂,本身就是个坏的编程风格),就很容易丢掉 break 语句而导致执行逻辑错误了。

申请内存时忽略了字符串结束符'\0'

1. 示范代码

#include

#include

#include

int main()

{

char *src_str = "Hello!";

int len = strlen(src_str);

char *dst_str = (char*)malloc(len);

printf("%d\n", len);

if(dst_str)

{

//strcpy(dst_str, src_str);

memcpy(dst_str, src_str, len);

printf("%s\n", dst_str);

free(dst_str);

}

return 0;

}

2. 错误分析

示范代码输出结果如下(多次运行程序,! 后面的字符输出结果都不太一样):

6

Hello!?

出错原因在于计算字符串长度时,忽略了字符串后面的 "\0"符号也占一个字符,上述代码,必须修改为 int len = strlen(src_str) + 1 才正确。

循环条件中边界错误导致越界

1. 示范代码

#include

int main()

{

int a[5], i;

/* Initiate the array */

for(i = 0; i <= 5; i++)

{

a[i] = i;

}

/* Print the array */

for(i = 0; i <= 5; i++)

{

printf("%d\t", a[i]);

}

return 0;

}

2. 错误分析

示范代码输出结果如下:

0 1 2 3 4 5

貌似越界了程序也没崩溃,一切正常!但是,这正是大项目中埋雷的“绝佳实践”,神不知鬼不觉, Bug 已在你手中诞生!等到某天程序突然崩溃或运行异常了,也不知道错在哪儿!

本示范代码由于错误地将循环条件中的 " i < 5 " 写成了 " i <= 5 ",导致访问数组越界,将把该数组低地址的一个整数空间给踩了。为了验证我所说的,将上述代码修改一下,如下所示:

#include

int main()

{

int a[5];

int b = 100;

int i;

printf("b = %d\n", b);

/* Initiate the array */

for(i = 0; i <= 5; i++)

{

a[i] = i;

}

/* Print the array */

for(i = 0; i <= 5; i++)

{

printf("%d\t", a[i]);

}

printf("\nb = %d", b);

return 0;

}

输出结果如下:

b = 100

0 1 2 3 4 5

b = 5

除了初始化变量 b 以外,我们只是对 b 进行打印操作,“理论上”应该不会改变它的值才对啊?!试想一下,如果是在某个复杂的算法函数中,在你毫无知觉的情况下,所使用的变量 b 已经被莫名其妙修改,你作何感想?现在能够理解我前面的话,不是危言耸听了吧?

总结

编程是一件严肃细致的工作,程序员,尤其是 C 语言程序员,必须时刻保持严谨细致的作风,一丝不苟,才能减少错误的发生,避免一不小心掉入 C 语言的陷阱中,然后在茫茫代码中寻找那由于自己粗心大意而造成的低级错误。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值