长字符串下Segmentation fault问题:自定义printf调用vfprintf崩溃求助
解决自定义printf风格函数的段错误问题
嘿,我来帮你捋捋这个段错误的事儿!你写的mr_asprintf是想把{i}替换成%d、{s}替换成%s,然后调用vfprintf对吧?格式字符串到23个字符左右就崩,核心问题肯定出在内存分配上——你看你一开始用calloc(1, sizeof(char))给newFormat只分配了1个字节的空间,这完全不够用啊!
问题根源
初始只分配1字节内存,后续拼接替换后的字符串时,必然会越界写入不属于你的内存区域。这种越界操作刚开始可能没触发问题,但当字符串长度达到某个值(比如你说的23字符)时,刚好踩坏了程序的关键内存(比如栈帧、堆管理结构),直接就触发Segmentation fault了。
修复思路和代码示例
要解决这个问题,得保证newFormat的内存能动态容纳替换后的内容,同时正确处理格式字符串的替换逻辑:
#include <stdio.h> #include <stdarg.h> #include <stdlib.h> #include <string.h> // 调整函数签名,符合asprintf的常规用法:返回写入长度,通过**ret返回分配的字符串 int mr_asprintf(char **ret, const char *format, ...) { va_list args; va_start(args, format); // 初始分配足够内存:原格式字符串长度的2倍(替换后字符数可能增加) size_t newFormatSize = strlen(format) * 2 + 1; char *newFormat = malloc(newFormatSize); if (!newFormat) { va_end(args); return -1; } newFormat[0] = '\0'; const char *ptr = format; char *newPtr = newFormat; while (*ptr != '\0') { if (*ptr == '{' && *(ptr + 1) != '\0') { // 匹配到{,检查后续是i还是s if (*(ptr + 1) == 'i') { strcpy(newPtr, "%d"); newPtr += 2; ptr += 2; // 跳过{i}两个字符 } else if (*(ptr + 1) == 's') { strcpy(newPtr, "%s"); newPtr += 2; ptr += 2; // 跳过{s}两个字符 } else { // 不是目标格式,直接复制{ *newPtr++ = *ptr++; } } else { // 普通字符,直接复制 *newPtr++ = *ptr++; } // 检查内存是否不足,不足则扩容 size_t usedBytes = newPtr - newFormat; if (usedBytes >= newFormatSize - 1) { newFormatSize *= 2; char *tempBuf = realloc(newFormat, newFormatSize); if (!tempBuf) { free(newFormat); va_end(args); return -1; } newFormat = tempBuf; newPtr = newFormat + usedBytes; } } *newPtr = '\0'; // 确保字符串以'\0'结尾 // 先计算需要的缓冲区大小,再分配内存写入 int writeLen = vsnprintf(*ret, 0, newFormat, args); if (writeLen > 0) { *ret = malloc(writeLen + 1); if (*ret) { vsnprintf(*ret, writeLen + 1, newFormat, args); } else { writeLen = -1; } } // 清理临时内存 free(newFormat); va_end(args); return writeLen; }
关键修改点
- 动态内存管理:初始分配足够的内存,并且在内存不足时用
realloc扩容,彻底避免越界 - 正确的格式替换:逐个字符遍历格式字符串,准确识别
{i}和{s}并替换 - 错误检查:所有内存分配操作都做了失败检查,避免内存泄漏和崩溃
- 符合asprintf规范:调整函数签名,通过指针返回分配的字符串,返回值为写入的字符数
内容的提问来源于stack exchange,提问作者F.MANNOU
相关产品推荐
相关产品推荐

