C语言自定义实现printf时%d格式符输出乱码触发段错误问题
故障原因
代码存在5个直接触发乱码和段错误的问题:
- 未初始化变量传入长度计算函数:
myPrintf中定义的局部变量j没有赋初始值,是栈上的随机垃圾值,把它传给string_length当递归计数起点,算出来的格式串长度完全错误,循环会越过格式串的\0结束符,持续读取非法内存地址的垃圾数据当字符打印,最终访问到无权限的内存地址触发段错误。 - 整数打印逻辑错误:当前
%d分支直接执行write_char(x + '0'),仅能正确打印0-9的单个正整数,遇到负数、大于9的多位数时,会把整数值直接当成ASCII码转换,输出完全错误的字符。 - 可变参数未正常收尾:使用
va_start初始化参数列表后,没有调用va_end做清理,属于C标准定义的未定义行为。 - 缺少边界判断:遇到
%后直接执行i++读取下一个字符,如果%是格式串的最后一个字符,会直接越界访问内存。 myPrintf函数没有定义返回值,执行到函数结尾时会返回栈上的随机值,同样属于未定义行为。
修复方案
直接替换为以下修正后的代码即可:
#include <unistd.h> #include <stdarg.h> int write_char(char c); int myPrintf(const char *format, ...); void print_int(int num, int *count); int main(void) { myPrintf("Let's try to printf a simple sentence.\n"); myPrintf("Hello%d\n", 1); myPrintf("Test negative: %d, test multi digit: %d\n", -42, 12345); return (0); } int myPrintf(const char *format, ...) { int i = 0, total_printed = 0; va_list args; va_start(args, format); while (format[i] != '\0') { if (format[i] != '%') { write_char(format[i]); total_printed++; } else { i++; // 处理%位于串末尾的边界情况 if (format[i] == '\0') break; switch(format[i]) { case 'd': { int x = va_arg(args, int); print_int(x, &total_printed); break; } case '%': write_char('%'); total_printed++; break; default: // 未知格式符原样输出 write_char('%'); write_char(format[i]); total_printed += 2; break; } } i++; } va_end(args); return total_printed; } // 处理整数打印,支持负数、多位数、int最小值边界 void print_int(int num, int *count) { if (num < 0) { write_char('-'); (*count)++; // 单独处理int最小值,避免取反溢出 if (num == -2147483648) { write_char('2'); (*count)++; num = 147483648; } else { num = -num; } } if (num > 9) { print_int(num / 10, count); } write_char(num % 10 + '0'); (*count)++; } int write_char(char c) { return write(1, &c, 1); }
核心修改点:
- 移除提前计算格式串长度的错误逻辑,循环直接以
format[i] != '\0'作为终止条件,从根源避免长度计算错误导致的越界。如果需要保留长度计算函数,移除多余的计数入参,从0开始计数即可,禁止传入未初始化的变量。 - 新增
print_int辅助函数,支持负数、多位数、int类型最小值(-2147483648)的正确打印,通过递归逐位拆分数字,再转换为对应ASCII字符输出。 - 补充
va_end(args)调用,完成可变参数列表的清理。 - 增加边界判断:处理
%后先判断是否到了字符串末尾,同时增加未知格式符的兜底逻辑、%%打印百分号的逻辑,避免越界。 - 给
myPrintf增加返回值,返回实际打印的字符总数,和标准库printf行为对齐。
内容的提问来源于stack exchange,提问作者Leuel Asfaw
相关产品推荐
相关产品推荐

