C语言的坑,你觉得哪些是语言本身的?你踩过吗?

来自:麻辣软硬件(微信号:VOSDeveloper),作者:达不优GY

我们都知道,C语言是一门很流行又有很多优点的编程语言,从产生到现在一直被众多的平台所选用,尤其是其运行效率更是甩Java等其他面向对象的编程语言几条街。C语言是一门值得尊敬的语言,但是C语言是否也有缺陷或者让你使用不爽的地方呢?本猿根据以前自己踩过的坑,和各位分享一下。

switch语句带来的麻烦

我们知道,switch语句的一般形式如下:

switch(表达式){
    case 条件1
        func1();
        break;
    case 条件2
        func2();
        break;
    default:
        break;
}

但是很多时候,我们是不是写成下面这样了呢?

switch(表达式){
    case 条件1
        func1();
    case 条件2
        func2();
    default:
        break;
}

这样的代码写出来,一旦执行某个case,程序将会依次执行后面所有的case,直到遇到break语句,这样的执行即所谓的“fall through”。但是现实的switch语句用法中,有大神统计在所有的case中缺省需要使用“fall through”的仅仅只占3%,即大多数情况的缺省都是错误的。
那么,C语言在设计中把“fall through”作为switch的缺省行为是不是一个失误呢?在绝大多数情况下你用switch语句的时候你不得不加上一条额外的break语句来改变这个行为。本猿在这个问题踩过至少2-3个想起来都是内牛满面的坑,您是不是也有同样的经历,有的话请公众号留言举个爪,咱们交流交流,哈哈哈~

字符串操作引发的相关问题

我们知道,ANSI C引入的一个新约定就是相邻的字符串常量被自动合并成一个字符串。这就省掉了在书写多行信息是在每一行的末尾加上“\”并且下一行还需要顶格写的做法。
我们来看下面一段代码:

#include <stdio.h>

void main(){

    printf("Hello world! "
    "Love means never having to say you’re sorry.\n");

    printf("Hello world! \
    Love means never having to say you’re sorry.\n"
);

}

运行结果如下:

可以看到,第一条语句中两个字符串会自动合并,这样写也许对于printf语句来说并没有什么影响,接下来我们再看一段代码:

#include <stdio.h>

void main(){
    char *action[] = {
        "paul",
        "we friend"
        "ship turned over",
        "hello world"
    };
    printf("%s\n",action[1]);   
}

上面这段代码运行的结果会是什么样呢?
we friend么 ?
我们看一下实际运行结果:

对了,你没有看错,友谊的小船说翻就翻了,哈哈~
由于两个字符串自动合并,导致结果跟原先的意思大相径庭,并且,字符串的数量比我们预期的少了一个,如果在程序中想要修改action数组中“hello world”的内容,而我们这个时候用action[3]来操作,这就导致数组操作越界了,很容易修改其他一些未知的内存导致程序崩溃。回忆起来满满都是泪啊!

一个微妙的BUG

我们来看一段代码:

#include <stdio.h>

int array[]={5,6,7,8,9,10,22,30};
#define TOTAL_NUM (sizeof(array)/sizeof(array[0]))
void main(){
    int num=-1,y=0;
    if(num < TOTAL_NUM-1){
        printf("num=%d\n",num);
        y=array[num+1];
        num++;
    }
    printf("exit %d\n",num);
}

各位觉得,这段代码会是什么样的运行结果呢?
没错,出乎我们的意料,结果是:

为什么会出现直接exit -1呢?
这是因为sizeof返回的值是无符号的,所以TOTAL_NUM所定义的类型也是无符号型,if语句中用int和unsigned int来做比较,所以num被默认升级为unsigned int类型,而-1转换成unsigned int的结果就是一个非常大的整数,所以导致if表达式条件不成立。这个bug是不是很微妙?又多两行泪~

讲个小故事

好了,眼泪多了,讲个小故事轻松一下吧,这是本猿以前看到的一个小故事,和C语言无关,和编程有关。
上个世纪60年代,美国有一个太空发射任务是将一个探测器放到金星上去,但是在发射后几分钟,地面控制中心就不得不将它摧毁,因为发射它的火箭开始偏离轨道。

经过几个星期的分析,问题被工程师们确定是发生在软件中,但这个软件的错误是算法上的抄写错误而不是程序本身的BUG。也就是说程序是严格按照程序员的设想去运行的,但是在软件的说明书上,指令本身却出现了错误。在数学中,变量符号上面加“ ̄”表示求平均,在提供给程序员的手写制导方程式中,这个符号不小心被漏掉了。程序员正常的按照算法编写了程序,并使用了从雷达指引的原始速度而不是平均速度。结果就是这个微小的差别导致了整个发射任务的失败!

这个小故事告诉我们,即使你可以保证你的编程100%可靠,你也有可能成为算法灾难性BUG的牺牲品。

最后的话

作为一枚程序猿,我们应该对自己所从事的工作心存敬畏,不管是C语言还是其他语言编程,讲不清的主观或者客观的原因,错误往往在我们不经意间制造。只有用做好产品的心态,用解决问题的心态积极对待每一行代码。才能很好的绕过或者填上各种“坑”。

对于编程,您是否也有好多想要分享的呢?欢迎后台给我们留言交流!

推荐↓↓↓
C语言与C++编程
上一篇:使用 VS 2019进行C++ for Linux远程开发 下一篇:HAProxy 2.0发布,长期支持版本