C语言缺陷及陷阱读书笔记(一)

词法陷阱

暑假的时候重新学习了C语言,这里记录一些学习的心得和体会.

1.1 "="不同于"=="

#include <stdio.h>
int main(void)
{
    ///"=="符号写成"="
    //这里出现"="与"=="的错误,由于将符号"=="写成"="号,导致c的值一直为32(' '符号的ASCII值),
    //因此这个while循环一直都为1,变成一个死循环.
    char c;
    while (c=' '||c=='\t'||c=='\n')
         c=getc(f);

    //可以通过显式地进行比较来避免这种问题
    if((x=y)!=0)
    //foo是程序示例中经常出现的函数名,经常出现的变量名为bar,两者经常一起搭配使用
    foo();


    ///"="符号写成"=="
    //下面的语句功能是filedesc存储函数open的返回值,然后通过比较返回值是否小于0来判定
    //open函数是否成功执行,但这里将"="符号写成"==",也就是本来的赋值操作变成了比较操作
    //比较的结果为0或者1,不会小于0.导致这个判定语句无法按照实现功能.
    if((filedesc==open(argv[i],0))<0)
        error();
}

"="是赋值运算符,"=="是比较运算符。两者的性质不同,混用会导致错误。

1.2 &和 |不同于 && 和 ||

1.概念区别

  • & 和 | 是按位运算符,对操作数的处理方式是将其视作一个二进制的位序列,分别对其每个位进行操作
  • && 和|| 是逻辑运算符,其对操作数的处理是将其视作“真”(一般用非0表示)或者“假”(一般用0表示),当结果为“真”时返回1,结果为“假”时返回0,也就是说其返回的值只能为0或者1,并且在表达式中,如果左操作数能够确定最终结果,右侧操作数就不会进行运算。

相关比较代码如下:

i=0;
while(i<tabsize && tab[i] !=x)
   i++;<code>

这是一段查找制定元素的检查代码,当等于tabsize时还没有找到x元素时停止循环。
下面将 “&&” 更改为 “&” 来查看其区别:

i=0;
while(i<tabsize & tab[i] !=x)
    i++;

这里代码可能还会可能继续工作,可能的原因如下:

  1. 在 & 两侧的比较运算的结果在“真”的时候为1,在“假”的时候为0,也就是说x和y的取值范围为0或者1,而按位运算得出的结果也是1或者0,即在这种情况下 x&y 等同于 x&&y。但是,如果在 & 两侧的结果用了除 “1“ 之外的数值来表示”真“的话,代码将无法工作。
  2. 假设程序计数变量i递增到tabsize时,如果是&&的话会跳过右边比较,因为左操作数的结果为0,已经确定了结果了。而按位运算符&则需要对两边操作数进行求值,它会继续检查”tab[i]!=x“这条语句,但tab[i]这个元素并不存在。这里仅仅是读取其数值,如果是对其进行引用的话就会出现错误。

1.3词法分析中的”贪心法“

#include <stdio.h>
int main(void)
{
    ///贪心法
    //每一个符号都应该包含尽可能多的字符,从左到右一个字符一个字符地读入,如果该
    //字符可能组成一个符号,那么再读入下一个字符,判断已经读入的两个字符组成的字符串
    //是否可能是一个符号的组成部分,如果可能,继续读入下一个字符,重复以上,直到读入的
    //字符组成的字符串已不再可能组成要给有意义的符号

    //示例1
    y=x/ *p;

    //示例2
    y=x/(*p);

    //示例3
    y=x/*p;

    //上面两个赋值操作的区别不一样,由于/*在编译器作为一个注释的开始,因此编译器会判定
    //示例3中/*是一个注释符号,而不断读入字符,直到*/
    //示例 1和示例2是对示例3的改进,同时也要注意对老版本的C语言中与现在C语言符号的差异性

}

1.4 整数常量###

#include <stdio.h>
int main(void)
{
    //输出数值操作
    struct {
            int part_number;
            char *description;

            }partable[]={

                        046,   "left-handed widget",
                        047,   "right-handed widget",
                        125,   "frammis"

                         };


    //上面的代码会输出两个8进制的值,其中046,047代表的是两个八进制的值
    //因为整型常量的第一个字符0是八进制的表示

}

1.5 字符和字符串

#include <stdio.h>
int main(void)
{
    ///字符串
    printf("Hello world\n");
    char hello1[]={'H','e','l','l','o',' ','w','o','r','l','d','\n','\0'};
    printf(hello1);
    //用双引号引起的字符串,代表的是一个指向无名数组起始字符的指针,该数组
    //被双引号之间的字符以及一个额外的二进制值为0的字符'\0'初始化,因此两
    //个printf()的输出一致


    ///字符
    //用单引号包括的字符其实是一个整数,对应在编译器采用的字符集中的序列值
    //因为'\0'的对应的整数值为0,因此下面将'\0'改为0,仍然得到相同的输出
    char hello2[]={'H','e','l','l','o',' ','w','o','r','l','d','\n',0};
    printf(hello2);



    ///字符和字符串两者混用的错误

    //这里'/'是对应的整型常量而不是指针,因此出错
    char *slash='/';

    //printf输出应该有双引号的字符串,而这里是单引号,因此出错
    printf('\n');

    return 0;

}

posted on 2015-09-20 11:30  陆游君语  阅读(216)  评论(0编辑  收藏  举报

导航