C语言指针与数组区别:仅存单变量地址的指针为何访问其他变量无编译错误
首先给出你提供的测试代码:
int main() { int b=1, c=3, e=4; int *a=&b; a[1]=c; a[2]=e; printf("%d, %d, %d\n", a[0], a[1], a[2]); return 0; }
你提到的两个问题分别解释如下:
编译阶段没有报错的原因
- C语言语法中,
a[N]本质是*(a + N)的语法糖,只要a是指针类型、N是整数类型,语法就是合法的。C语言的设计理念是信任程序员,默认不会在编译期或者运行期做数组越界、指针非法偏移的检查,因此不会因为指针偏移超过原指向变量的范围就抛出编译错误。 - 编译器只会记录
a是int*类型的指针,不会额外存储它指向的是单个int变量还是长度为N的int数组,因此a[1]、a[2]的写法完全符合语法要求,编译可以正常通过。
指针可以访问到c、e变量的原因
- C标准确实不要求同代码块内的独立局部变量在内存中连续对齐排布,但这属于C标准留给编译器的自行实现的权限,不代表编译器不能将同类型局部变量分配在连续内存上。你当前测试环境的编译器(如默认配置的GCC、Clang),刚好将
b、c、e三个同类型的栈上局部变量按连续地址分配,地址偏移和a[0]、a[1]、a[2]的指针偏移匹配,因此刚好能读取到另外两个变量的值。 - 这个结果完全是编译器实现的巧合,不属于C语言的标准特性:更换编译器、开启不同优化等级、更换CPU架构,都可能出现变量排布不连续的情况,此时运行代码可能输出乱码、触发段错误,甚至出现其他完全不可预期的异常。
重要提示
这种写法属于典型的未定义行为,C标准明确规定指针偏移超过所指向对象的合法内存边界后解引用的行为没有任何约束,绝对不能在生产代码中使用这种写法。
内容的提问来源于stack exchange,提问作者Richard
相关产品推荐
相关产品推荐

