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

C函数栈数组跨调用保留值的原因探究

栈内存残留与字符串终止符缺失的问题解析

你遇到的问题本质是局部栈内存未初始化和字符串缺少终止符共同导致的,拆解来看:

1. 栈内存的复用与残留特性

函数里的buffer[64]是局部变量,存储在栈帧中。C语言默认不会为局部栈变量初始化值,函数返回后,栈帧会被标记为可复用,但内存里的旧数据不会被主动清零。当你多次调用make_label时,操作系统大概率会给这个函数分配同一块栈内存区域,这就导致前一次调用存在buffer里的字符会残留下来。

比如你的测试案例:

  • 第一次处理#start,buffer里写入了s-t-a-r-t(5个字符),此时buffer[5]及以后的内存是未初始化的垃圾值,但碰巧第一次后续字节里有'\0',所以printf能正常输出start;
  • 第二次处理#loop,只写入了l-o-o-p(4个字符),buffer[4]还是上一次留下的t,printf找不到终止符,就会把loopt一起输出;
  • 第三次处理#ignore,写入了6个字符,刚好覆盖了之前残留的t以及后面的垃圾值,且后续碰巧有'\0',所以输出正常;
  • 第四次处理#end,只写入3个字符,buffer[3]及以后是上一次ignore留下的r-e,所以printf输出endore。

2. printf的无终止符行为

printf打印字符串时,会从传入的地址开始逐个输出字符,直到遇到'\0'才停止。如果没有手动添加终止符,它会一直读取后续内存字节,直到碰巧遇到'\0'或者触发内存访问错误——你这里属于前者,刚好能读到之前残留的字符和偶然的'\0'。

3. 你的疑问解答

不是数组被初始化为0,恰恰相反,栈内存是未初始化的垃圾值,加上函数重复调用复用了同一块栈空间,才导致前一次的字符残留。如果栈内存真的自动初始化为0,你根本不会遇到这种问题,printf会在有效字符后立刻停止。

修复方案

在循环结束后,必须手动给buffer添加字符串终止符,同时要注意防止数组溢出(另外原代码中FILE参数需要传指针,否则编译会报错):

uint32_t make_label(FILE *f) {
  uint8_t i=0;
  char c;
  char buffer[64];
  while ( (c = fgetc(f)) != ' ' && i < 63 ) { // 限制i不超过63,留一个位置给'\0'
    buffer[i++] = c;
  }
  buffer[i] = '\0'; // 手动添加字符串终止符
  // 处理标签的逻辑
  return 1;
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.01 16:25:24