zoukankan      html  css  js  c++  java
  • C语言缺陷及陷阱读书笔记(一)

    词法陷阱

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

    1.1 "="不同于"=="

    #include <stdio.h>
    int main(void)
    {
        ///"=="符号写成"="
        //这里出现"="与"=="的错误,由于将符号"=="写成"="号,导致c的值一直为32(' '符号的ASCII值),
        //因此这个while循环一直都为1,变成一个死循环.
        char c;
        while (c=' '||c=='	'||c=='
    ')
             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
    ");
        char hello1[]={'H','e','l','l','o',' ','w','o','r','l','d','
    ',''};
        printf(hello1);
        //用双引号引起的字符串,代表的是一个指向无名数组起始字符的指针,该数组
        //被双引号之间的字符以及一个额外的二进制值为0的字符''初始化,因此两
        //个printf()的输出一致
    
    
        ///字符
        //用单引号包括的字符其实是一个整数,对应在编译器采用的字符集中的序列值
        //因为''的对应的整数值为0,因此下面将''改为0,仍然得到相同的输出
        char hello2[]={'H','e','l','l','o',' ','w','o','r','l','d','
    ',0};
        printf(hello2);
    
    
    
        ///字符和字符串两者混用的错误
    
        //这里'/'是对应的整型常量而不是指针,因此出错
        char *slash='/';
    
        //printf输出应该有双引号的字符串,而这里是单引号,因此出错
        printf('
    ');
    
        return 0;
    
    }
  • 相关阅读:
    [转] KVM I/O slowness on RHEL 6
    QEMU KVM libvirt 手册(3)
    QEMU KVM libvirt手册(2): monitor
    QEMU KVM libvirt 手册(1): 安装
    CentOS7下JSP连接Mysql
    使用Tomcat搭建基于域名的虚拟机
    CentOS7下搭建Tomcat服务器
    Nginx在线服务状态下平滑升级或新增模块
    源码安装LNMP
    二进制包安装Mysql
  • 原文地址:https://www.cnblogs.com/luyoujun/p/4823102.html
Copyright © 2011-2022 走看看