zoukankan      html  css  js  c++  java
  • C陷阱与缺陷的个人知识点摘录

    编译过程的一点心得体会:
    .h文件其实只在预处理的过程用到,用来将类似#include <stdio.h>这样的行展开为具体内容。
    那些标准库或者其他库中的函数,是在链接的过程中连接器把相应部分从库中提取出来的,和头文件无关,头文件其实只是做一个函数声明,使编译通过。

    Chapter 1:

    1.词法分析的贪心贪心法,即大嘴法:每一个符号应该包括尽可能多的字符。
    2.如果一个整型常量的第一个字符是数字0,那么该常量会被视作是八进制数。
    3.不要使用嵌套注释这种东西,即使编译器支持。


    Chapter 2:
    1.加法运算符的优先级高于移位运算符。
    2.单目运算符是自右向左结合的。
    3.任何一个逻辑运算符的优先级低于任何一个关系运算符。
    4.移位运算符的优先级比算术运算符,但是比关系运算符
    5.如果声明结尾的分号被省略,编译器可能会把声明的类型视作函数的返回值。


    Chapter 3:

    1.C语言只有一维数组,而且数组的大小在编译期就作为一个常数确定下来

    2.确定一个数组,只能做两件事情,确定该数组的大小,和获取指向该数组下标为0的元素的指针。

    3.malloc函数使用时候要考虑无法提供请求内存的情况,该情况会返回一个空指针,用完后一定要释放。

    4.使用malloc为字符串分配空间的时候需要注意一点,strlen计算的字符串长度是不包括结尾的''的,因此在申请的时候需要考虑是否加+1.

    5.main函数中的main(int argc,char* argv[]),argv[]中的元素为字符指针类型。

    6.n++和实际过程是,先保存n,从n中+1,然后将保存值进行相应运算后再执行,而往往++n比n++更有效率。

    7.数组中实际不存在的溢界元素的地址位于数组所占内存之后,这个地址可以用于进行赋值和比较,当然如果要引用该元素就是非法的了。

    8.逗号运算符,先对左侧操作数进行求值,然后该值被丢弃,然后再对右侧操作数进行求值。
    分隔函数参数的逗号运算符并非逗号运算符。例如,x和y再函数f(x,y)中的求值顺序是未定义的,而在函数g((x,y))中却是先x,后y的顺序。再后面的这个例子中,函数g的参数只有一个。(x,y)便是进行上述的逗号运算符。

    9.赋值运算符不保证任何求值顺序。例子:从数组x中复制前n个元素到数组y中。
    int i = 0;
    while(i<n)
    {
        y[i] = x[i++];
    }
    5
    1
    int i = 0;
    2
    while(i<n)
    3
    {
    4
        y[i] = x[i++];
    5
    }
    因为此时不确定这个赋值语句中y[i]实在i++之前被赋值还是i++之后被赋值。
    正确的写法:
    int i = 0;
    while(i < n)
    {
        y[i] = x[i];
        i++;
    }
    6
    1
    int i = 0;
    2
    while(i < n)
    3
    {
    4
        y[i] = x[i];
    5
        i++;
    6
    }

    10.运算符&和&&不同,运算符&两侧的操作数都必须被求值。

    11.判断有符号整数溢出的方式(当然也只有有符号整数才有溢出的情况)
    int a = 0;
    int b = 0;
    if((unsigned)a+(unsigned)b>INT_MAX)
        complain();
    
    
    或者是不转换成无符号
    if(a>INT_MAX-b)
        complain();
    x
    1
    int a = 0;
    2
    int b = 0;
    3
    if((unsigned)a+(unsigned)b>INT_MAX)
    4
        complain();
    5
    6
    7
    或者是不转换成无符号
    8
    if(a>INT_MAX-b)
    9
        complain();

    12.一个返回值为整数的函数如果返回失败(没有return)则实际上是隐含的返回了某个“垃圾”整数。
    该数是未知的,如果用不到,确实没什么关系,但是为了安全起见,函数的一般加上return 0;或者exit(0);

    Chapter 4:
    1.如果一个函数再被定义或者声明之前被调用,那么他的返回类型就默认为整型。
    2.scanf和printf的时候,如果"%d",但是给的量是char,那么就会覆盖其他内存或者读到其他的量的聂村区域。
    3.保证一个特定的名称的所有外部定义在每个目标模块中都有相同的类型。
    例子:一个文件中定义 char filename[] = "/etc/passwd";
    另一个文件中声明extern char* filename;
    虽然数组和指针非常的相似,但是两者使用的存储空间方式是不同的。

    Chapter 5:
    1.如果要对文件同时进行输入和输出操作,必须在其中插入fseek函数的调用。

    Chapter 6:
    1.宏定义调用的时候注意输入参数可能产生的多次自加活着自减类似操作。
    2.宏定义的调用时,注意宏定义内部的if之类的语句和外部紧接着的else 之类的语句。
    3.使用宏定义定义新类型的时候,当其中的类型为指针时
    例如#define T1 struct foo *
    T1 a,b;这样定义出来的a为结构体指针变量,b为结构体变量。

    Chapter 7:





  • 相关阅读:
    【LOJ】 #2015. 「SCOI2016」妖怪
    【LOJ】#2016. 「SCOI2016」美味
    【LOJ】 #2008. 「SCOI2015」小凸想跑步
    【LOJ】#2007. 「SCOI2015」国旗计划
    【LOJ】#2006. 「SCOI2015」小凸玩矩阵
    【LOJ】#2172. 「FJOI2016」所有公共子序列问题
    【LOJ】#2173. 「FJOI2016」建筑师
    【LOJ】#2174. 「FJOI2016」神秘数
    【LOJ】#2280. 「FJOI2017」矩阵填数
    【洛谷】P4585 [FJOI2015]火星商店问题
  • 原文地址:https://www.cnblogs.com/LyndonMario/p/9326073.html
Copyright © 2011-2022 走看看