sprintf无法获取第0个字符串?C语言代码运行结果异常求助
缓冲区溢出导致的未定义行为分析
咱们先回到你最初的错误代码——char item[3];这行是导致问题的核心。
为什么会出现溢出?
当你执行sprintf(item, "%-7s", list[i]);时:
%-7s的作用是把字符串左对齐,并且填充到7个字符宽度。对于list[0]的"One",会生成"One "(3个字符+4个空格,总共7个可见字符)。- 但C字符串必须以
'\0'(空字符)结尾,所以这行sprintf实际需要写入8字节的数据(7个可见字符+1个终止符)。 - 而你定义的
item只有3字节的空间,sprintf不会检查缓冲区大小,会直接往内存里写超出的字节——这就是缓冲区溢出,属于C语言里的未定义行为。
为什么第二次循环丢失了"One"?
栈上的变量通常是连续存放的(具体取决于编译器,但这种情况很常见),item和list在栈里的位置大概率是相邻的。当第一次循环处理list[0]时,溢出的字节直接覆盖了list[0]所在的内存区域,把原来的"One"改成了空字符串或者其他无效内容。等到第二次循环读取list[0]时,它已经不是原来的字符串了,自然打印不出来。
修正方案
- 保证缓冲区足够大:把
item的大小改成char item[8];(7个字符+1个终止符),这样能容纳%-7s生成的所有内容。 - 使用更安全的函数:推荐用
snprintf替代sprintf,它可以限制写入的字节数,避免溢出:
这样即使格式字符串要求的长度超过缓冲区,也只会写入缓冲区能容纳的最大字节数,并自动加上终止符。snprintf(item, sizeof(item), "%-7s", list[i]);
补充说明
当你把item改成char item[7];时,其实还是差1字节的终止符空间,虽然可能在某些环境下没触发问题,但严格来说依然存在溢出风险,改成8字节或者用snprintf才是稳妥的做法。
内容的提问来源于stack exchange,提问作者mike65535
相关产品推荐
相关产品推荐

