程序设计分组训练实验一

实验一必备知识

csdn-vs调试

[bilibili生成目录word]
https://www.bilibili.com/video/BV1V14y1t73F/?share_source=copy_web&vd_source=668d4d374b623b9a00fbe541e1b24f78

数组指针退化

数组名一旦充当地址,就会退化!!!

  1. 数组名作为函数参数传递时
    • 当把数组名作为函数参数传递给函数时,数组名会退化为指向数组首元素的指针。例如:
    void func(int arr[]) {
        // 这里的arr实际上是一个指针,等价于int* arr
    }
    
    int main() {
        int a[5];
        func(a);
        return 0;
    }
    
    • 在这个例子中,amain函数中是一个数组名,代表整个数组。但是当它被传递给func函数时,a就退化为一个指向int类型的指针(int*),在func函数内部,arr不再具有数组的长度信息等数组特性,仅仅是一个指针。
  2. 使用取地址运算符&取数组名的地址(取整个数组的地址)之外的情况
    • 在表达式中,如果数组名不是取整个数组的地址(&数组名)的情况,数组名都会退化为指向首元素的指针。例如:
    int a[5];
    int* p=a; // 这里a退化为指向首元素的指针,所以可以赋值给int*类型的p
    
    • 另外:
    int a[5];
    sizeof(a); // 这里a表示整个数组,结果为5 * sizeof(int)
    
    • 但是如果写成:
    int a[5];
    int* p = a;
    sizeof(p); // 这里p是指针,结果为sizeof(int*)
    

sizeof()是操作符,不会引发数组退化

sizeof是一个编译时操作符,它的作用是获取操作数所占用的字节数。当操作数是数组名时,sizeof会将数组名视为整个数组对象,而不是指向数组首元素的指针。
在 C 语言中,数组的大小是其类型的一部分。例如,对于int a[5];,数组a的类型是int[5],这个类型信息在编译时是确定的。
当计算sizeof(a)时,编译器根据数组的定义直接计算出整个数组所占用的字节数,即5 * sizeof(int)(假设sizeof(int)为 4 字节,那么sizeof(a)为 20 字节)。

关于数组名

1. 对于二维数组int a[4][4]

  • 从数组的存储角度来看,二维数组在内存中是按行顺序存储的,a可以看作是一个指向包含4个int元素的数组的指针(即a的类型是int(*)[4])。

2. 分析*a + 1

  • 根据运算符优先级,*的优先级高于+
  • 首先,*a等价于a[0],它是指向数组a的第一行(即a[0]是一个包含4个int元素的数组,在这里它会退化为指向该数组首元素的指针,类型为int*)。
  • 那么*a+1就是在a[0]的基础上偏移一个int类型的单位。如果a的起始地址为0x1000(假设),a[0]的值也是0x1000(因为a[0]是第一行数组的首地址),*a + 1的值就是0x1000 + sizeof(int)(假设sizeof(int)=4,则值为0x1004),它指向了a[0][1]这个元素。

3. 分析*(a + 1)

  • 这里a+1表示将指针a(类型为int(*)[4])向下移动一行(因为指针的偏移量是sizeof(int[4]))。如果a的起始地址为0x1000a+1的值就是0x1000+sizeof(int[4]) = 0x1000 + 16(假设sizeof(int)=4),它指向了数组a的第二行(即a[1])。
  • 然后*(a + 1)就等价于a[1],它是一个包含4个int元素的数组,同样会退化为指向该数组首元素的指针(类型为int*),它指向a[1][0]这个元素。

()和[]

[]优先级高于()

  1. 对于(*(a + 2))[3]
    • 根据C语言中数组和指针的运算规则:
      • a是一个二维数组名,它可以被看作是一个指向数组(这个数组包含4个int元素)的指针。
      • a+2表示将指针a向后移动2个“单位”,这里的“单位”是指包含4个int元素的数组的大小。所以a + 2指向二维数组a中的第三行(行索引从0开始)。
      • *(a + 2)就是取a+2所指向的那一行数组。
      • 最后(*(a + 2))[3]表示取这一行数组(也就是第三行)中的第4个元素(列索引从0开始),在给定的初始化中a[2][3]=12
  2. 对于*(a + 2)[3]
    • 根据运算符优先级,先计算(a + 2)[3]
      • (a+2)是一个地址,(a + 2)[3]等价于*((a + 2)+3)。这表示将a + 2这个地址再向后移动3个“单位”(每个单位是包含4个int元素的数组的大小),然后取这个地址指向的内容。实际上,这是越界访问,因为原始的二维数组a只有4行,这样的计算导致访问到了非法的内存区域。
      • 然后再对这个非法访问得到的结果进行间接访问(*操作),由于访问的是非法内存,所以得到的是一个未定义的值,这里显示为-858993460,这个值是完全不可预测的,不同的编译器、不同的运行环境可能会得到不同的结果。
posted @   sunrise0307  阅读(35)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)
点击右上角即可分享
微信分享提示