求助:使用realloc收缩字符串时输出垃圾值(需移除空格与数字)
问题分析与修复方案
我帮你梳理下代码里的关键问题,这几个点是导致输出垃圾值和内存逻辑混乱的原因:
核心问题点
- 缺少字符串结束符:C语言的字符串必须以
'\0'结尾,你的代码完全没处理这个,所以printf读取时会一直读到内存里的垃圾数据。 - 错误的
realloc时机:你现在遇到要删除的字符就立刻缩小内存,这会导致后续写入有效字符时可能出现内存越界——比如提前把内存缩得太小,后面要写的字符没地方放了。而且这种边遍历边调内存的方式既低效,也不符合你“精确内存空间”的需求。 - 初始内存分配逻辑不合理:一开始就分配和原字符串一样大的内存,完全没必要,我们可以先统计需要保留的字符数,直接分配刚好够的内存。
修复后的完整代码
我重写了clearDigitsAndSpaces函数,调整了内存分配逻辑,同时补上了字符串结束符的处理:
#define _CRT_SECURE_NO_WARNINGS #include <malloc.h> #include <stdio.h> #include <assert.h> #include <stdlib.h> #include <string.h> /* Function declarations */ void Ex1(); char* clearDigitsAndSpaces(char*); void Ex2(); void Ex3(); int main() { int select = 0, i, all_Ex_in_loop = 0; printf("Run menu once or cyclically?\n(Once - enter 0, cyclically - enter other number) "); if (scanf("%d", &all_Ex_in_loop) == 1) do { for (i = 1; i <= 3; i++) printf("Ex%d--->%d\n", i, i); printf("EXIT--->0\n"); do { select = 0; printf("please select 0-3 : "); scanf("%d", &select); } while ((select < 0) || (select > 3)); switch (select) { case 1: Ex1(); break; case 2: Ex2(); break; case 3: Ex3(); break; } } while (all_Ex_in_loop && select); return 0; } void Ex1() { char input[] = "abcd2 34fty 78 jurt#"; char *temp = NULL; temp = clearDigitsAndSpaces(input); printf("%s\n", temp); // 去掉了多余空格,避免输出格式混乱 free(temp); } char *clearDigitsAndSpaces(char *old_string) { int count = 0; int i = 0; int j = 0; int len = strlen(old_string); // 第一步:先统计需要保留的字符数量 while (old_string[i]) { if (old_string[i] != ' ' && !(old_string[i] >= '0' && old_string[i] <= '9')) { count++; } i++; } // 精确分配内存:有效字符数 + 1个'\0'结束符的空间 char *new_string = (char *)malloc((count + 1) * sizeof(char)); assert(new_string); // 内存分配失败检查 // 第二步:复制有效字符到新字符串 i = 0; while (old_string[i]) { if (old_string[i] != ' ' && !(old_string[i] >= '0' && old_string[i] <= '9')) { new_string[j++] = old_string[i]; } i++; } new_string[j] = '\0'; // 必须添加字符串结束符,否则是非法C字符串 return new_string; } void Ex2() { } void Ex3() { }
关键修复说明
- 先统计再分配:先遍历一遍原字符串,数清楚要保留的字符数
count,直接分配count + 1字节的内存(多1字节存'\0'),完全满足你“精确内存空间”的要求。 - 补上结束符:复制完有效字符后,给新字符串末尾加上
'\0',确保它是合法的C字符串,彻底解决垃圾值问题。 - 移除无效的
realloc:去掉了边遍历边调整内存的逻辑,代码更高效、更易读,也避免了内存越界的风险。 - 优化条件判断:把原来的
(old_string[i] > '9' || old_string[i] < '0')改成了!(old_string[i] >= '0' && old_string[i] <= '9'),逻辑一致但可读性更好。
现在运行代码,就能得到你预期的输出abcdftyjurt#了。
内容的提问来源于stack exchange,提问作者0xDEADBEEF
相关产品推荐
相关产品推荐

