C语言指针越界访问疑问:为何两类越界操作执行结果不同?
C语言指针越界相关问题解答
核心认知纠正
- 你提到第一段代码会出现编译错误,这个认知有误:这段代码不存在语法错误,绝大多数编译器都能正常编译通过,运行时出现的异常属于未定义行为,不属于编译阶段的错误。
- 指针本身只存储内存地址,不会自带绑定的内存范围信息,C语言标准也没有要求编译器做运行时的内存边界检查。越界访问是否会触发崩溃,完全取决于访问的内存地址是否属于当前进程的可操作范围,以及是否覆盖了关键内存数据。
- 指向单个变量的指针和指向数组首元素的指针,在C语言的类型系统中完全一致,指向的内存后续有没有连续的合法空间,由开发者自行保证,编译器不会做相关判断。
两个代码片段的差异说明
字符串操作代码的合法性
char str[] = "hello" 声明的是一块连续分配的char数组,实际内存长度为6字节(5个可见字符+末尾自动添加的'\0'结束符)。
strB指向数组首元素str[0],根据C语言数组指针运算规则,指向数组元素的指针做加法偏移时,会自动定位到相邻的下个数组元素,strB + 1对应的就是合法的数组元素str[1],所以*(strB + 1) = 'E'是完全合法的操作,不存在越界问题。- 后续循环访问
strB + i时,当i≥5就属于越界访问,这部分属于未定义行为。你当前运行能输出垃圾值,只是刚好对应内存属于当前进程可读取的范围,换运行环境大概率会出现崩溃、乱码等不可预期的结果。
int指针操作的问题
C语言标准完全没有规定独立声明的局部变量的内存排布顺序:
- 你假设
d+1对应变量c或者a的地址,这个假设本身不成立。编译器可能会根据优化策略调整变量的存储顺序,也可能在变量之间插入内存对齐用的填充字节,d+1指向的地址大概率不属于任何你显式声明的变量,可能是栈上的返回地址存储区、只读区域,或者是未分配的内存空间,写入操作就会直接触发段错误或者程序运行异常。 - 这段代码也不是100%无法运行,如果你调整编译参数关闭优化,也有可能刚好
d+1指向了c的地址实现写入成功,但这完全属于不可控的巧合,不能作为合法代码的依据。
内容的提问来源于stack exchange,提问作者Eric
相关产品推荐
相关产品推荐

