• 第3章 语义陷阱


    3.1 指针与数组

    1. C 语言只有一维数组,且数组的大小必须在编译期就确定。数组中的元素可以是任意类型。
    2. 对于数组,除了确定数组的大小和获得指向下标为 0 的元素的指针外,其他的对于数组的操作都是通过指针进行的,表现为以数组下标操作。
    int a[3];
    
    • 1

    该语句声明了 a 是一个拥有3个整型元素的数组。

    strcut {
        int p[4];
        double x;
    }b[17];
    
    • 1
    • 2
    • 3
    • 4

    表示数组 b 有17个元素,每个元素都是一个结构体,结构体中包含一个4个元素的整型数组 p 和一个双精度类型变量 x 。

    int calendar[12][31];
    
    • 1

    二维数组的声明,表示该数组有12个数组类型的元素,每个元素都是一个拥有31个整型元素的数组。(先12后31)

    1. 任何指针都指向某种类型的变量,指针初始化时,右侧必须是地址值
    2. 如果一个指针指向的是数组中的元素,那么对指针的加减操作就相当于对数组下标的操作。
    3. 指针加一,表示指向内存中的下一个变量的首地址,而不是原指针所指向的地址加一,具体地址值移动多少,取决于指针所指向变量的类型。
    4. 指向同一数组的两个指针,可以通过加减互相得到。指向不同数组的两个指针,即便所指向的地址在内存中正好间隔一个数组元素的整数倍,结果也未必是正确的。
    5. 数组名代表指向下标为 0 的元素的指针,&a代表指向数组的指针,而不是指向数组的第一个元素。
    6. 特殊情况,sizeof(数组名),计算的是整个数组的大小,而不是指向数组的元素的指针的大小。
    7. a[2]2[a]含义相同
    8. 二维数组的数组的每一个“行”下标都代表一个数组的首地址,数组的大小由“列”值决定。

    3.2 非数组的指针

    非数组情况主要是对字符串的操作。
    合并字符串:

    char *r , *malloc();
    //动态申请空间,大小为两个字符串长度加一个'\0'字符
    r = malloc(strlen(s) + strlen(t) +1);   
    //如果malloc运行失败,会返回一个空指针
    if(!r)
    {
        complain();   //输出错误提示
        exit(1);
    }
    strcpy(r,s);
    strcat(r,t);
    
    //一段时间后释放malloc分配的空间
    free(r);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    3.3 作为参数的数组说明

    1. C语言会自动地将作为参数的数组声明转换为对应的指针声明。
    int strlen(char a[])  
    {             }
    等同于
    int strlen(cahr* a)  //指针参数不代表数组,仅代表数组的第一个元素的地址
    {             }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    1. 指针参数代表一个数组,如main函数的第二个参数:
    maiun(int argc, char* argv[])   //强调的重点在于argv是一个指向某数组的起始元素的指针,且该数组的元素为字符指针类型
    {        }
    等同于
    maiun(int argc, char** argv)
    {        }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    3.4 避免“举隅法”

    C语言中复制指针时,并不复制指针所指向的内存数据,所以复制后的指针与原指针指向同一个地址的内存数据,改变任意一个指针所指向的内容,另一个指针所指向的内容也会改变,因为本质是同一个数据。

    3.5 空指针并非空字符串

    C语言中,对于空指针,不能使用该指针所指向的内存中存储的内容,不能作为函数的参数进行调用,

    3.6 边界计算与不对称边界

    int i, a[10];
    for( i=1; i<=10; i++ )
    {
        a[i] = 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    本意是将数组 所有元素置 0,当 i 等于 10 时,超出数组长度,计数器 i 会被赋值 0 ,所以会陷入死循环。

    不对称边界,用第一个入界点和第一个出界点表示一个数值范围入界点包含在取值范围内,出界点不包含在取值范围内,例如:

    x >= 16 && x <= 37 改为 x >= 16 && x < 38
    
    • 1

    这样写的好处有:

    1. 取值范围大小就是上下界之差。
    2. 如果取值范围为空,即上界等于下界。
    3. 即使取值范围为空,上界也永远不可能小于下届。

    3.7 求值顺序

    3.8 运算符&&、||和!

    3.9 整数溢出

    3.10 为函数main提供返回值















    -------------------------持续更新--------------------------

  • 相关阅读:
    Cadence Allegro PCB设计88问解析(十五) 之 Allegro中如何替换过孔类型
    Python机器学习实战-特征重要性分析方法(8):方差分析ANOVA(附源码和实现效果)
    nginx配置多个服务域名
    Jetson TX2 刷机
    服务器数据恢复-服务器系统损坏启动蓝屏的数据恢复案例
    军用FPGA软件 Verilog语言的编码准测之触发器、锁存器
    [Spring Framework]DI依赖注入②(自动装配、集合注入)
    上传文件-读取excel文件数据
    一点笔记--关于P!=NP、AI、chatGPT
    RabbitMQ集群运维实践
  • 原文地址:https://blog.csdn.net/zmhDD/article/details/125894611