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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.27 04:09:24