C语言未初始化数组指针:操作2、3是否会引发非法内存访问?
int (*p)[10];的操作风险分析 先明确核心原则:未初始化的p存储的是随机垃圾地址,但只有当代码尝试实际访问指针指向的内存内容时,才会触发非法内存访问的运行时错误;单纯的指针算术、甚至一次解引用(仅做类型转换而非内存读取)都不会直接引发错误。
先回忆int (*p)[10];的类型:p是一个指向包含10个int的数组的指针。
逐个操作拆解
操作1:
(p+1)
这是单纯的指针算术:因为p指向的是10个int的数组,p+1会计算出"下一个同类型数组"的地址。整个过程只是做地址计算,未访问任何内存,所以不会报错。操作2:
(p+1)[2]
按C语言的下标规则,a[b]等价于*(a + b),所以这个操作等价于*( (p+1) + 2 ),也就是*(p+3)。这里的解引用只是把p+3这个指向数组的指针,转换成指向该数组第一个int的指针——这个转换过程不需要读取数组里的任何内容,只是地址的类型转换,没有实际访问内存,因此不会触发运行时错误。操作3:
p[2]
等价于*(p+2),和操作2逻辑完全一致:解引用指向数组的指针,得到数组类型后隐式转为指向首元素的指针,全程没有读取内存里的具体值,所以不会报错。操作4:
*p[2]
注意运算符优先级,[]比*高,所以这个操作等价于*(p[2]),也就是*( *(p+2) )。这里*(p+2)先得到一个指向int的随机垃圾指针,然后再对这个指针解引用——这一步会尝试读取该地址对应的int值,属于实际访问内存,必然触发非法内存访问的运行时错误。
结论
操作2和3不会导致非法内存访问,它们只是完成了指针算术和一次类型转换性质的解引用;只有操作4因为进行了二次解引用,实际尝试读取内存内容,才会触发运行时错误。
内容的提问来源于stack exchange,提问作者Khushit Shah

