• 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;
    
    }
  • 相关阅读:
    每日一水 POJ8道水题
    编译和使用 MySQL C++ Connector
    j2ee model1模型完成分页逻辑的实现 详解!
    DB查询分析器访问EXCEL时,要在表名前后加上中括弧或双引号
    指向结构体变量的指针
    EOSS V3.0 企业运营支撑系统(基于RBAC原理的权限管理)
    MybatisGen1.0 Mybatis JavaBean Mapper生成工具
    The table name must be enclosed in double quotation marks or sqare bracket while accessing EXCEL by
    资源-Android:Android
    软件-开发软件:Android Studio
  • 原文地址:https://www.cnblogs.com/luyoujun/p/4823102.html
Copyright © 2020-2023  润新知