实验一必备知识
[bilibili生成目录word]
https://www.bilibili.com/video/BV1V14y1t73F/?share_source=copy_web&vd_source=668d4d374b623b9a00fbe541e1b24f78
数组指针退化
数组名一旦充当地址,就会退化!!!
- 数组名作为函数参数传递时
- 当把数组名作为函数参数传递给函数时,数组名会退化为指向数组首元素的指针。例如:
void func(int arr[]) { // 这里的arr实际上是一个指针,等价于int* arr } int main() { int a[5]; func(a); return 0; }
- 在这个例子中,
a
在main
函数中是一个数组名,代表整个数组。但是当它被传递给func
函数时,a
就退化为一个指向int
类型的指针(int*
),在func
函数内部,arr
不再具有数组的长度信息等数组特性,仅仅是一个指针。
- 使用取地址运算符
&
取数组名的地址(取整个数组的地址)之外的情况- 在表达式中,如果数组名不是取整个数组的地址(
&
数组名)的情况,数组名都会退化为指向首元素的指针。例如:
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
的起始地址为0x1000
,a+1
的值就是0x1000+sizeof(int[4]) = 0x1000 + 16
(假设sizeof(int)=4
),它指向了数组a
的第二行(即a[1]
)。 - 然后
*(a + 1)
就等价于a[1]
,它是一个包含4个int
元素的数组,同样会退化为指向该数组首元素的指针(类型为int*
),它指向a[1][0]
这个元素。
()和[]
[]优先级高于()
- 对于
(*(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
。
- 根据C语言中数组和指针的运算规则:
- 对于
*(a + 2)[3]
- 根据运算符优先级,先计算
(a + 2)[3]
。(a+2)
是一个地址,(a + 2)[3]
等价于*((a + 2)+3)
。这表示将a + 2
这个地址再向后移动3个“单位”(每个单位是包含4个int
元素的数组的大小),然后取这个地址指向的内容。实际上,这是越界访问,因为原始的二维数组a
只有4行,这样的计算导致访问到了非法的内存区域。- 然后再对这个非法访问得到的结果进行间接访问(
*
操作),由于访问的是非法内存,所以得到的是一个未定义的值,这里显示为-858993460
,这个值是完全不可预测的,不同的编译器、不同的运行环境可能会得到不同的结果。
- 根据运算符优先级,先计算