C高级篇(非BUG的语言特性)

    许多新手程序员经常会犯的一种错误,就是将 i = 3; 与 i == 3 相互混淆,前者表示一个赋值语句,而后者常常作为判断的条件。还有的程序员想将指针指向NULL时,写成了p == NULL; 这样的话变成了什么?不过不用担心,这种错误编译器能够辨别。
    NUL与NULL:在C语言中,NUL表示一个字符串的结束,用字符表示为'\0',我们通常用'\0'这种字符常量作为判断条件而不是NUL。NULL表示为空,用NULL表示什么也不指向(即空指针)。
    switch、case、default:在用switch的时候,每个case后要加上一个break语句,除非你想让后面的case一一执行,那样看起来比没使用switch还要麻烦。break语句总是靠近最近的循环语句或者switch语句,请注意你的代码风格,不要低估它的影响,它曾经导致AT&T历史上第一次重大的网络瘫痪。代码如下:
    C高级篇(非BUG的语言特性)_第1张图片
    能看出只进行了case THING1: 然后直接跳出了整个switch吗?
    
    在ANSI C下引入了一种新风格,如下:
    
    C高级篇(非BUG的语言特性)_第2张图片
    但是如果我们将s中的第四个字符串后面的逗号去掉,那么这个char指针就只有三个元素了,而后面的循环输出的是四个元素。这样会发生什么错误?越界了,因为我们之前定义的字符串常量只有三个,这里却引用了四个,第四个哪来的?问内存管理器去。
    
    C语言运算符优先级存在的问题也有许多,例如说.运算符高于*,然而*p.f表示什么?有人可能会误解为(*p).f,但实际上是*(p.f)。
    []高于*,例如int *ap[],有人可能误解为ap是个指向int数组的指针,但实际上ap是个元素为int指针的数组,也就是指针数组。
    函数()高于*,例如int *fp(),有人可能误解fp是个函数指针,函数返回int,但是实际上却是返回int *的fp。
    总之,最好在我们办公的位置上贴上一张优先级表,方便查看,在写程序的时候也要时常注意。若我们对优先级判断失误,整个代码的意思就有可能收到影响,我想象你不希望这样。除了优先级外,还要考虑语句的结合性,有些是左结合有些是右结合,当几个操作符具有相同的优先级时决定先执行哪一个。例如:
    int a,b = 2,c = 3;
    a = b = c;
    第二个语句赋值符优先级都一样,所以考虑其结合性,赋值符具有右结合性,就是说表达式中最右边的操作最先执行,然后从右向做执行。最终a的值为3。

    早期gets()中的Bug导致了Internet蠕虫,就在1988年11月,蠕虫程序入侵了数千台接入Internet的计算机,而最终原因却是因为gets()函数没有对读入的字符数设置一个限制。我们知道字符数组的空间是堆栈自动分配的,当用户输入超过了这个数组的规定字符,gets()函数将会继续把多出来的字符压到堆栈中。如果黑阔想通过这些多余的字符来改邪堆栈中某个项目的内容,那···不解释,这个在高级技术貌似叫缓冲区溢出攻击。可以用fgets来代替gets,例如:
    *c = fgets(s,sizeof(s),stdin);    //fgets(源,n-1字符数,欲读取的流)
    这样函数就不会超出缓冲区的范围,也不会由于其他人运行程序而覆盖堆栈中的重要区域。

    空格:许多人会告诉你空格在C语言中并没有什么意义,你喜欢的话可以随便输入几个或者少输入几个,但事实并非如此!空格可以帮我们构造良好的代码风格,提高程序的通读性。例如:z = y+++++x;
    这样的话会出现编译错误,但是我们加上必要的空格:z = y++ + ++x;
    还有另一种关于空格的错误,就是z = *x/*y; 表面上我们看到的是将两个指针变量的值相除,但在仔细思考,我们发现/*是注释符呀,这样就出错了。但是多加个空格z = *x / *y;
    
    是的,我们在用C进行开发的时候,可能会遇到由于C的语言特性产生的错误,这方面的案例太多太多了,有的因为将“,”写成“.”而损失了上千万。我想你一定不希望自己有这样的遭遇,那么就需要你留个心眼,考虑程序是否存在逻辑错误或者实体(语句)错误。

你可能感兴趣的:(C语言)