C语言字符数组越界访问输出异常字符的原因求解
C语言数组越界访问出现原字符串内容的底层原理
核心前提
C语言语法本身不提供数组边界检查,超出数组合法下标范围的访问属于未定义行为:只要访问的内存地址属于当前进程的合法地址空间,程序就不会直接崩溃,输出结果由当前内存的实际存储内容决定。
代码前置问题
你初始化str数组的代码存在隐含问题:
char str[5] = "Hello";
字符串字面量"Hello"实际包含6个字符(末尾隐含结束符'\0'),你指定数组长度为5,编译器只会复制前5个字符H e l l o到str中,不会自动补'\0'。这导致你第一个遍历字符串的while循环会越界访问str[5]的位置才找到结束符,最终循环结束时i=5,为后续操作埋下了越界隐患。
栈内存布局是该现象的核心原因
函数内的局部变量默认分配在栈内存区域,栈的生长方向为从高地址向低地址分配:先定义的变量会被分配到更高的内存地址,后定义的变量分配到更低的内存地址。
你的两个数组在当前运行环境的栈上内存排布(从低地址到高地址)大致如下:
偏移量(相对于rev数组首地址) | 所属区域 | 存储内容 |
|---|---|---|
| -5 ~ -1 | 栈其他区域 | 程序运行残留的无用数据 |
| 0 ~ 4 | rev[0]~rev[4] | 反转后得到的o l l e H |
| 5 | 栈对齐填充位 | 你运行结果中出现的空字符 |
| 6 | str[1] | 原字符串的e |
| 7 | str[2] | 原字符串的l |
| 8 | str[3] | 原字符串的l |
| 9 | str[4] | 原字符串的o |
| 10 ~ 13 | 栈其他区域 | 清零的内存/填充数据 |
| 14 | 栈变量残留区 | 恰好存储了H对应的ASCII值 |
| 15及以上 | 栈其他区域 | 乱码数据 |
你用rev[k]访问超过下标4的位置时,实际已经读到了更高地址的str数组内存空间,所以会输出原字符串的内容;k为负数时是读取rev数组更低地址的栈残留数据,所以输出乱码,这些都是当前环境内存布局的正常体现。
注意
这种越界访问的结果完全不具备通用性,不同编译器、编译选项、运行环境下的输出可能完全不同,实际开发中必须严格避免数组越界访问。
内容的提问来源于stack exchange,提问作者Nagraju Kasarla
相关产品推荐
相关产品推荐

