zoukankan      html  css  js  c++  java
  • 《C陷阱和缺陷》读书笔记-其二:语义陷阱

    第三章 语义陷阱

    1、指针和数组

    (1)对于数组:

    C语言中只有一维数组,且数组的大小必须在编译器间就作为一个常数确定下来,数组的元素可以是任何类型的对象;
    
    对数组的操作只有两个,确定数组的大小,以及获得指向该数组下标为0的元素的指针。
    
    

    (2)如果一个指针指向数组中的一个元素,对指针加一就可以获取指向数组中下一个元素的指针,对指针减一可以获取指向该数组中前一个元素的指针,加减n类似。针对指向数组元素的指针的加减,实际上是移动对应元素的指向。

    (3)数组名通常可以认为是数组中下标为0的元素的指针,例外情况是在sizeof(a)中,其结果是整个数组的大小,而不是单个元素的大小,因此,常用以下表达式求取数组长度sizeof(a) / sizeof(a[0])

    (4)数组名a可以表示数组下标为0的元素的指针,则数组下标为0的元素的值可以用*a来表示;又因为数组指针可以加减,则a + 1表示下标为1的元素的指针,a + n表示下标为n的元素的指针(n小于数组长度);进一步,数组下标为1的元素的值为*(a + 1),数组下标为n的元素的值为*(a + n),通常简写为a[n]。

    (5)对于二维数组,如int calendar[12][31];,calendar是一个有着12个数组类型元素的数组,每个数组类型元素又是一个有着31个整型元素的数组;可以理解为,每31个整数构成的一个数组,合并成一个大元素,12个这样的元素组合成一个新的数组,即二维数组:

    calendar[0]: 30个整数组成一个大元素
    calendar[1]: 30个整数组成一个大元素
    calendar[2]: 30个整数组成一个大元素
    calendar[3]: 30个整数组成一个大元素
    calendar[4]: 30个整数组成一个大元素
    calendar[5]: 30个整数组成一个大元素
    calendar[6]: 30个整数组成一个大元素
    calendar[7]: 30个整数组成一个大元素
    calendar[8]: 30个整数组成一个大元素
    calendar[9]: 30个整数组成一个大元素
    calendar[10]: 30个整数组成一个大元素
    calendar[11]: 30个整数组成一个大元素
    

    个人对二维数组的理解,可以扩展到多维:
    calendar[i]里面存放的是一个地址,该地址指向第i个大元素的首地址;
    这个12个地址组成一个一维数组,而calendar是这个一维数组的首地址,因此,calendar表示指向第0个大元素的地址,由于指针的可加性,*(calendar + i)表示指向第i个大元素的地址,简写为calendar[i];
    有了大元素的首地址,如果需要获取大元素中某个元素的值,可以用
    (*(calendar + i) + j)表示,其中i表示第i个大元素,j表示对应大元素中的第几个元素,简写为calendar[i][j]。

    (6)数组指针的应用:
    如上,calendar表示存放第一个大元素地址的地址,即指向大小为31的int数组的指针;
    定义如下变量:int (*monthp)[31];
    monthp是一个指针,该指针指向的是一个大小为31的int数组,与calendar意义相同,因此可以这样写:
    monthp = calendar; 或者 monthp = calendar[i];

    (7) 字符串

    字符串常量代表了一块包括字符串中所有字符以及一个空字符('')的内存区域的地址,所以字符串常量本质上是一个地址。

    字符串以空字符''作为结束标志,但是库函数strlen返回参数中字符串所包括的字符数目时并不计算这个空字符串;因此需要分配空间时,需要特别注意为末尾空字符分配一个字符空间。

    (8)数组作为入参
    将数组名作为参数传递时,C语言会自动将作为参数的数组声明转化为相应的指针声明,即指向该数组第一个元素的指针;
    int strlen(char s[])会被退化成int strlen(char *s)

    2、不对称边界

    (1)数组元素下标从0开始;

    (2)不对称边界通用原则:
    其一:首先考虑最简单情况下的特例,然后将得到的结果往外推;
    其二:仔细计算边界,绝对不能掉以轻心。

    (3)数组中实际不存在的“溢界”元素的地址位于数组所占内存之后,这个地址可以用于进行赋值和比较,但是不能引用。

    3、整数溢出

    如果算术运算符的一个操作数时有符号整数,另一个是无符号整数,那么有符号整数会被转换成无符号整数,不会发生“溢出”;如果两个操作数都是有符号整数,“溢出”就有可能发生;

    当发生整数溢出时,做出任何假设都是不安全的。

    4、其他

    (1)指针与指针所执行的数据有区别:指针是指向一个区域的起始地址,而对应的数据是该区域的内容,其内容长短指针无法确定,但是其内容的数据类型必须与指针的类型相匹配;且通过指针的加减访问的范围也仅局限于该区域,否则会发生不可预期的错误,即指针越界。

    (2)将常数0强制转换成指针,不等于任何有效的指针,即我们常用的空指针(#define NULL 0);
    此外,将其他整数转换为一个指针,得到的结果依赖于编译器的实现。

    (3)求值顺序:&& 和 || 首先对左侧操作数求值,只有在需要时才对右侧进行求值;三目运算符?: 根据判断条件,再确定求取哪一个表达式的值;逗号表达式,先对左侧操作数求值,然后该值丢弃,继续对右侧求值;

    赋值运算符不保证任何求值顺序。

    (4)建议给main函数添加返回值,0代表程序执行成功,非0表示程序执行失败。

  • 相关阅读:
    5.19 省选模拟赛 T1 小B的棋盘 双指针 性质
    5.15 省选模拟赛 容斥 生成函数 dp
    5.15 省选模拟赛 T1 点分治 FFT
    5.15 牛客挑战赛40 B 小V的序列 关于随机均摊分析 二进制
    luogu P4929 【模板】舞蹈链 DLX
    CF 878E Numbers on the blackboard 并查集 离线 贪心
    5.10 省选模拟赛 拍卖 博弈 dp
    5.12 省选模拟赛 T2 贪心 dp 搜索 差分
    5.10 省选模拟赛 tree 树形dp 逆元
    luogu P6088 [JSOI2015]字符串树 可持久化trie 线段树合并 树链剖分 trie树
  • 原文地址:https://www.cnblogs.com/HZL2017/p/14916662.html
Copyright © 2011-2022 走看看