为什么两段使用未初始化C指针的C代码一段报段错误一段可运行?
问题原因解释
核心前提
两段代码均存在严重的未定义行为,第二段代码所谓的“可以正常运行”只是特定环境下的偶然现象,不代表代码本身符合C语言规范,也不具备可移植性。
共同错误根源
两段代码都存在「未初始化指针解引用写入」的问题:
- 局部非静态变量在C语言中不会被自动初始化,定义的
int *p分配在函数栈帧上,存储的是栈内存中残留的随机垃圾值,即p指向完全随机的内存地址。 - 执行
*p = 10时,相当于向这个随机地址写入数据,操作后果完全不可预测,属于C语言标准明确规定的未定义行为。
运行表现差异的底层原因
差异本质是栈帧布局变化导致p的随机指向地址属性不同:
- 第一段代码的main函数栈帧中仅存在
int *p一个局部变量,栈上残留的垃圾值刚好让p指向了当前进程无访问权限的地址(比如系统预留的非法地址、只读内存段地址),写入操作触发操作系统的内存保护机制,直接抛出段错误。 - 第二段代码新增了
char c = 'c'的局部变量定义,编译器分配栈空间的结构、栈上残留的垃圾值内容都发生了变化,此时p存储的随机垃圾值刚好落在当前进程拥有写权限的内存区域(比如当前进程的栈空间、可写数据段区域),所以写入操作没有触发系统异常,表面看起来“正常运行”。但此时已经发生了非法内存写入,可能破坏进程自身的合法数据,后续运行依然存在崩溃、逻辑异常等不可预测的风险。
正确写法参考
必须先让p指向合法的可写内存,再进行解引用操作,示例:
#include <stdio.h> int main() { int num; int *p = # // 让p指向合法的int变量地址 *p = 10; printf("%d", *p); // 输出10,运行完全稳定 return 0; }
或者使用堆内存:
#include <stdio.h> #include <stdlib.h> int main() { int *p = malloc(sizeof(int)); // 申请堆内存 if (p != NULL) { *p = 10; printf("%d", *p); free(p); // 记得释放内存 } return 0; }
内容的提问来源于stack exchange,提问作者Abdullah Almariah
相关产品推荐
相关产品推荐

