C语言中popen()调用后使用printf()出现异常输出的问题求助
C语言popen配合printf异常输出的根本原因
所有异常的核心逻辑,都来自对C语言字符串操作基本规则的违反,不存在popen本身的特殊影响:
- C语言中使用
%s格式输出的字符串,必须以ASCII值为0的'\0'作为显式终止符,缺失终止符的字符串操作属于未定义行为,输出结果完全取决于内存随机残留值。 - 栈上定义的局部数组如果没有显式初始化,内存空间的残留值是随机的,直接用于字符串操作会彻底破坏字符串的连续性。
初始未修改版本的异常来源
- 代码中定义的
output[1000]、result[9]都是栈上未初始化的局部数组,没有内置的'\0'终止符。strncat的工作逻辑是从目标数组起始位置向后扫描,找到第一个'\0'才会开始追加内容,在没有合法终止符的场景下,追加过程完全不受控,甚至会越界破坏其他栈内存。 - 执行
memcpy(result, position + 8, sizeof(result))时,拷贝长度刚好等于result数组的总大小(9字节),会把从position+8开始的连续9个字节全部覆盖到result的存储空间中,整个result数组没有预留任何位置存放'\0'终止符。 - printf处理
%s格式时,会从result的首地址开始连续读取内存,直到碰到随机位置的'\0'才会停止,因为缺失合法终止符,最终就会输出和预期完全不符的杂乱内容。
修正部分代码后的异常来源
三处调整(output全零初始化、result全零初始化、memcpy从position起始位置拷贝)只解决了数组未初始化的问题,核心bug依然存在:
- ls命令的输出为逐行排列,每个文件名后会附带一个换行符
'\n'。定位到的position是"test.app"字符串的起始地址,从该位置连续拷贝9个字节时,前8个字节刚好是"test.app"的完整字符,第9个字节是紧跟在文件名后的换行符。 - 由于拷贝长度刚好等于result数组的总大小(9字节),整个result的存储空间会被全部填满,最初初始化的全零值会被memcpy完全覆盖,数组里依然没有留下任何位置存放
'\0'终止符。 - printf用
%s输出时,因为找不到合法终止符,会从result的起始位置一直向后读取栈上的残留内存——这块内存恰好是之前popen读入的ls完整输出(包含middle.txt、test.app、test.c的逐行内容),直到碰到栈上随机的'\0'才会停止,最终就会出现把所有ls输出都打印出来的异常结果。
正确的处理逻辑需要给字符串预留终止符位置:如果要在9字节大小的result数组中存放"test.app"字符串,需要只拷贝8个文件名字符,再手动给最后一个位置赋值
'\0',保证字符串合法性。
内容的提问来源于stack exchange,提问作者Francesco
相关产品推荐
相关产品推荐

