美文网首页
《C陷阱与缺陷》笔记

《C陷阱与缺陷》笔记

作者: DayDayUpppppp | 来源:发表于2019-01-09 11:54 被阅读0次
    第一章 词法陷阱
    1. 整数常量
        int a = 010;      //如果整数常量的第一个字符是0开头的,那么该常量表示的是八进制
        int a = 10;
        //上面两个定义是完全不一样的,第一个是八进制表示的。
      
    第二章 语法陷阱
    1. 理解函数声明

      float f;
      float f();
      float *f;
      float *f();
      float (*f)();
      
      float (*f)();   //函数声明,函数的参数是void,返回值是float
      (*f)();    //执行对应的地址的函数
      
      (float (*)())  
      //"指向返回值是float参数是void的函数指针的"的类型转换符
      
      // typedef 简化函数指针类型
      float add(float a,float b)
      {
          cout<<a<<"  "<<b<<endl;
          return a+b;
      }
      
      typedef float(*pfunType)(float, float);
      
      int main()
      {
          pfunType p = add;
          p(3.33, 2.22);
          return 0;
      }
      
    2. 注意作为结束语句的分号
      if之后不小心多写了一个分号

      if(a>b);   //一不小心多写了一个分号
      a = 100;
      

      那么,代码变成

      if(a>b) {  }
      a = 100;
      
    第三章 语义陷阱
    1. 指针与数组
    • 声明

      int * p;
      int arr[];
      
    • 定义

      int * p = &val;
      int arr[]=[1,2,3,4,5];
      
    • sizeof

      char * p = "1234567";
      sizeof(p);   // 4 ,指针的大小
      strlen(p);    //
      
      char arr[]="1234567";
      sizeof(arr);   //8,字符串的真实的大小,包含最后的\n
      
    1. 非数组的指针
      char * p = NULL;
      //试图打印内存地址是0的内容
      printf("printf null addr : %s \n",p);     //这个行为是未定义的,取决于不同的编译器的实现方式
      
    第四章 连接
    1. 检查外部类型

      • 分析下面的代码:
        file_a.c

        int val = 100;
        

        file_b.c

        extern char val;
        cout<<val<<endl;
        

        文件的定义的类型和外部声明的类型,不一致,会出现什么情况?

        大多数编译器不能检出这样的错误,所以,这是一种很危险的行为。尤其是下面的这个情况

        char  p[] = "1234567";   //定义是数组,却声明为指针
        
        char * p;   //定义是数组,却声明为指针
        cout<<p[1]<<endl;    //妥妥的core掉
        

      原因:

    2. 头文件

      • 头文件的“比较科学”写法:
        头文件只写对应.c文件里面的变量声明
    //head.h
    extern int config_ip;
    extern int config_pwd;
    
    int config_ip;
    int config_pwd;
    
    static int val;   //不对外部可见
    
    第六章 预处理

    基本用法:

    #宏常量
    #define num 100
    
    #宏函数
    #define max(a,b)  return a>b?a:b
    #define swap(a,b) \
      int tmp = a;\
      a = b;\
      b = tmp;
    

    但是,宏的本质是文本替换,但是在很多场景下面会出现问题。用inline和const更加安全一点。

    #define max(a,b) a>b?a:b
    
    max(a,b)+1;
    //替换之后,a>b?a:b+1       //和原来的有一些歧义,在某些case上面是错误的。
    
    1. typedef (类型定义)与宏的区别

      • 区别1: 比宏更加安全的定义
      typedef char* PCHAR;
      PCHAR pa,pb;  // = char * pa;char * pb;
      
      如果写成宏的话,可能是这样
      #define PCHAR char
      PCHAR pa,pb;   // = char * pa,pb; //= char * pa; char pb;
      
      • 区别2:用在旧的C代码中,帮助struct。
      // 用在旧的C代码中,帮助struct。以前的代码中,声明 
      // struct新对象时,必须要带上struct,
      // 即形式为: struct   结构名对象名,如:
      struct tagPOINT1
      {
        int x;
        int y; 
      } ;
      struct tagPOINT1 p1;
      
      //而在C++中,则可以直接写:结构名对象名,即:        
      tagPOINT1 p1;
      typedef struct tagPOINT
      {
        int x;
        int y;
      }POINT;
      POINT p1; // 这样就比原来的方式少写了一个struct,比较省事,
      
      • 区别3:
        在原来的声明里逐步用别名替换一部分复杂声明,如此循环,把带变量名的部分留到最后替换,得到的就是原声明的最简化版。
      原声明:int *(*a[5])(int, char*);
      变量名为a,直接用一个新别名pFun替换a就可以了:
      typedef int *(*pFun)(int, char*); 
      原声明的最简化版:
      pFun a[5]; 
      
      • 关于typedef


        image.png

    相关文章

      网友评论

          本文标题:《C陷阱与缺陷》笔记

          本文链接:https://www.haomeiwen.com/subject/kqcbrqtx.html