You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

从内存角度分析C语言偏移int地址定义字符串报错的原因

问题说明

已知前提假设:局部变量内存地址按从高地址到低地址方向分配。
原实现思路:

  • 通过char类型指针实现字符串存储,定义char指针并初始化为&a - 4,预期该指针指向int型变量a低地址方向偏移4字节的位置
  • 在scanf()中使用"%4s"格式控制符限制最多读取4个字符,认为读取的4个字符会依次存入&a-4、&a-3、&a-2、&a-1对应的内存地址

测试代码如下:

int main()
{
    int a = 5;
    char *string =  &a - 4;
    
    scanf("%4s", string);
    printf("%s", string);
    
    return 0;
}

代码运行时触发异常错误,以下为内存层面的具体原因分析。

内存层面错误原因

代码存在三个核心内存问题,直接触发异常:

  1. 指针运算逻辑完全错误,偏移量远超预期
    C语言的指针偏移以指针指向的类型长度为单位,而非按字节计算偏移。&a是int*类型指针,常规编译环境下sizeof(int)为4字节,因此&a - 4的实际偏移量是4 * sizeof(int) = 16字节,完全不是预期的4字节偏移。这个地址大概率已经跳出当前main函数的栈帧范围,指向未被程序分配写入权限、甚至未映射到进程地址空间的内存,scanf执行写入操作时会直接触发段错误。
  2. 对%4s格式符的行为理解错误,必然发生内存越界写入
    就算修正指针偏移逻辑,把地址计算改为按字节偏移的(char*)&a - 4,对%4s的行为认知也存在偏差:%4s中的数字4仅限制最多读取4个非空白输入字符,但scanf会自动在读取到的字符序列末尾追加1个'\0'作为字符串终止符,也就是说实际会往指定内存地址写入5字节数据,比预期多1字节。多写的终止符会越界覆盖相邻内存,如果相邻位置存放了栈保护校验值(canary)、函数返回地址这类关键数据,会直接被编译器插入的栈保护逻辑检测到,触发程序异常终止。
  3. 手动计算局部变量偏移的行为本身属于未定义行为
    默认的局部变量内存布局假设本身就不具备可移植性,甚至在同一编译器下不同优化等级都可能变化。C标准从未规定局部变量的栈分配顺序、栈对齐规则,编译器在编译阶段可能对变量位置做重排、插入对齐填充字节、栈保护字段,手动硬编码偏移计算地址的行为本身不受语言规范保障,访问这类地址的结果完全不可预期,出现内存错误是必然结果。

内容的提问来源于stack exchange,提问作者EternallyLoveLyJoy

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.28 08:27:19