C语言中free()调用后字符串指针出现乱码的问题求解
C语言malloc/realloc/free使用问题排查与解决
我接触C语言不到两个月,最近在使用malloc、realloc和free时遇到了问题。我写了一个print_num函数,功能是把整数转成字符串后打印,count用来记录打印的字符数,代码如下:
int print_num(int num, int count) { int i = 0, len; char last, *ptr2, *ptr = (char *)malloc(sizeof(char)); if (num == 0) return (print_char('0', count)); if (num < 0) count = print_char('-', count); num = abs(num); while (num != 0) { last = (num % 10) + '0'; if (i == 0) *(ptr) = last; else { ptr2 = (char *)realloc(ptr, i + 1); *(ptr2 + i) = last; ptr = ptr2; } num /= 10; i++; } len = strlen(ptr); for (i = len; i > 0; i--) count = print_char(ptr[i - 1], count); free(ptr); return (count); }
问题是:如果不调用free(ptr)或free(ptr2),代码运行正常,但多次调用这个函数时,字符串指针ptr末尾会出现乱码。比如连续调用两次:
print_num(39, 0); print_num(39, 0);
得到的输出是:
Length:[39, U�39]
删掉free(ptr)后代码正常,但会造成内存泄漏,请问该怎么解决?
附print_char函数实现:
int print_char(char c, int count) { write(1, &c, 1); return (count + 1); }
问题根源
你的代码有两个核心问题:
- 分配的内存没有以空字符
'\0'结尾:strlen依赖字符串末尾的'\0'来计算长度,你用malloc/realloc分配的内存只存储了数字字符,没有添加终止符,导致strlen会读取到内存里的随机垃圾数据,出现乱码。 - 未检查内存分配失败的情况:malloc和realloc都可能返回NULL,直接使用会导致程序崩溃,这个隐患必须处理。
修复方案
基础修复版(保留原逻辑)
核心是给字符串添加终止符,同时检查内存分配结果:
int print_num(int num, int count) { int i = 0, len; char last, *ptr2, *ptr = (char *)malloc(sizeof(char)); // 检查malloc是否成功 if (ptr == NULL) return count; if (num == 0) { free(ptr); // 提前释放分配的内存 return print_char('0', count); } if (num < 0) count = print_char('-', count); num = abs(num); while (num != 0) { last = (num % 10) + '0'; if (i == 0) { *ptr = last; } else { ptr2 = (char *)realloc(ptr, i + 1); if (ptr2 == NULL) { // 检查realloc是否成功 free(ptr); return count; } *(ptr2 + i) = last; ptr = ptr2; } num /= 10; i++; } // 关键:重新分配内存,添加字符串终止符 ptr2 = (char *)realloc(ptr, i + 1); if (ptr2 != NULL) { ptr = ptr2; } ptr[i] = '\0'; // 写入终止符 len = strlen(ptr); for (i = len; i > 0; i--) count = print_char(ptr[i - 1], count); free(ptr); return count; }
优化版(减少内存分配次数,避免溢出)
可以提前计算数字的位数,一次性分配足够内存,还能解决abs(INT_MIN)的溢出问题(INT_MIN的绝对值超过int的范围):
int print_num(int num, int count) { int temp = num; int digits = 0; char *ptr; int i; if (num == 0) return print_char('0', count); // 处理负数,用-temp代替abs避免INT_MIN溢出 if (num < 0) { count = print_char('-', count); temp = -temp; } // 计算数字的位数 while (temp != 0) { digits++; temp /= 10; } // 一次性分配内存,包含终止符的位置 ptr = (char *)malloc(digits + 1); if (ptr == NULL) return count; temp = num < 0 ? -num : num; i = digits; ptr[i] = '\0'; // 先写入终止符 // 从后往前填充数字字符 while (temp != 0) { i--; ptr[i] = (temp % 10) + '0'; temp /= 10; } // 直接从前往后打印,无需反转 for (i = 0; ptr[i] != '\0'; i++) count = print_char(ptr[i], count); free(ptr); return count; }
说明
- 基础修复版保留了你原有的逻辑,只补充了终止符和内存检查,适合你理解原有代码的问题。
- 优化版更高效,避免了多次realloc的开销,还处理了边界情况,是更健壮的实现。
内容的提问来源于stack exchange,提问作者Alex
相关产品推荐
相关产品推荐

