C语言指针疑问:为何p[5]=98能修改数组a[2]的值?
C语言指针访问数组元素的疑问解答
刚接触C语言时,你可能会遇到这个依赖栈布局的指针问题:
原代码与需求
原代码如下:
#include <stdio.h> int main(void) { int n; int a[5]; int *p; a[2] = 1024; p = &n; /* * write your line of code here... * Remember: * - you are not allowed to use a * - you are not allowed to modify p * - only one statement * - you are not allowed to code anything else than this line of code */ /* ...so that this prints 98\n */ printf("a[2] = %d\n", a[2]); return (0); }
原代码输出a[2] = 1024,要求添加一行代码,满足不能使用变量a、不能修改p、仅一行代码的约束,让输出变为a[2] = 98。
找到的解决方案是添加p[5] = 98;,修改后代码:
#include <stdio.h> int main(void) { int n; int a[5]; int *p; a[2] = 1024; p = &n; /* * write your line of code here... * Remember: * - you are not allowed to use a * - you are not allowed to modify p * - only one statement * - you are not allowed to code anything else than this line of code */ p[5] = 98; /* ...so that this prints 98\n */ printf("a[2] = %d\n", a[2]); return (0); }
为什么p[5] = 98;能修改a[2]?
这个写法完全依赖于局部变量在栈上的特定存储布局,属于C语言的未定义行为(换编译器、平台或编译选项就可能失效),但在题目假设的环境下,逻辑是这样的:
- C语言中,
p[k]等价于*(p + k):指针p会先加上k个int类型的字节偏移(k * sizeof(int)),再解引用访问对应地址的内容。 - main函数的局部变量
n、a[5]、p都存在栈上,题目环境的栈布局满足:&a[2] = &n + 5 * sizeof(int)(即a[2]的地址比n的地址高5个int的长度)。 - 因为
p = &n,所以p + 5正好指向a[2]的地址,p[5] = 98就等价于直接给a[2]赋值98。
⚠️ 注意:这种写法在实际开发中绝对不能使用,它完全依赖特定实现,没有可移植性,还属于栈内存越界访问,可能导致程序崩溃或其他不可预测的问题。
内容的提问来源于stack exchange,提问作者Sunkanmi
相关产品推荐
相关产品推荐

