字符指针数组排序程序无法正确读取输入单词问题排查
解决字符指针数组排序时的垃圾字符问题
我想实现一个程序,对元素为char指针的数组中的单词列表进行排序并展示。我用malloc为每个元素分配内存,通过read_line函数把输入的单词存到元素里,但问题是每个单词都包含随机垃圾字符,好像程序没正确读取并存储我输入的字符。我试过用strcpy、strcat,还调整过读取和内存分配代码的顺序,都没解决问题。以下是我的代码:
#include <stdio.h> #include <string.h> #include <stdlib.h> #include <ctype.h> #define MAX 100 #define LEN 20 int string_compare(const void *n, const void *m); int read_line(char *str, int n); int main(void) { int i, num_words, largo; char *list[MAX], word[LEN+1]; for (i=num_words=0; i<MAX; i++, num_words++) { printf("Enter word: "); list[i] = malloc(LEN + 1); if (list[i] == NULL) { printf("Error, no more memory available\n"); break; } largo = read_line(word, LEN) ; // 不知道为什么函数读取的字符串是随机字符(垃圾值) if (largo == 0) // break; // break已经生效 printf("Copying string %s...\n",list[i]); strcpy(list[i], word); } qsort(list, i, 21 * sizeof(char), string_compare); printf("In sorted order: "); for (i=0; i < num_words; i++) printf("Displaying...\n"); printf("%s ", list[i]); return 0; } int string_compare(const void *n, const void *m) { return strcmp((char *) n, (char *) m); } int read_line(char *str, int n) { int ch, i=0; while ((ch=getchar()) != '\n') if (i < n) str[i++] = ch; str[i] = '\0'; return i; }
代码中的关键错误
- 未初始化内存提前打印:在
strcpy(list[i], word);之前就执行printf("Copying string %s...\n",list[i]);,此时list[i]是刚malloc的未初始化内存,里面全是随机垃圾字符,这会让你误以为是read_line读取错误,但实际上是打印时机错误。 - qsort参数错误:qsort的第三个参数是数组中每个元素的字节大小,
list是char*类型的数组,每个元素是指针,应该传sizeof(char*)而非21 * sizeof(char)。错误参数会导致qsort排序时错误操作内存,破坏数据。 - 循环缩进错误:输出排序结果的for循环中,只有
printf("Displaying...\n");在循环体内,printf("%s ", list[i]);在循环体外。这会导致只打印一次提示,然后访问越界的list[num_words],输出垃圾值。 - string_compare类型转换错误:qsort传入的参数是数组元素的指针(即
char**),直接转成char*传给strcmp,会让strcmp比较指针地址而非字符串内容。 - read_line函数缺陷:未处理输入缓冲区残留字符(输入超长时,多余字符会留在缓冲区干扰后续读取),也未处理EOF(用户按Ctrl+D/Ctrl+Z),会导致死循环。
修正后的代码
#include <stdio.h> #include <string.h> #include <stdlib.h> #include <ctype.h> #define MAX 100 #define LEN 20 int string_compare(const void *n, const void *m); int read_line(char *str, int n); int main(void) { int i, num_words, largo; char *list[MAX], word[LEN+1]; for (i=num_words=0; i<MAX; i++) { printf("Enter word: "); list[i] = malloc(LEN + 1); if (list[i] == NULL) { printf("Error, no more memory available\n"); break; } largo = read_line(word, LEN); if (largo == 0) { free(list[i]); // 空输入时释放内存,避免泄漏 break; } strcpy(list[i], word); num_words++; // 仅成功读取单词时计数 } // 修正qsort参数:每个元素是char*,大小为sizeof(char*) qsort(list, num_words, sizeof(char*), string_compare); printf("In sorted order: "); for (i=0; i < num_words; i++) { printf("%s ", list[i]); free(list[i]); // 释放内存,避免泄漏 } printf("\n"); return 0; } // 修正类型转换:n和m是char**,解引用后得到字符串指针char* int string_compare(const void *n, const void *m) { return strcmp(*(char **)n, *(char **)m); } int read_line(char *str, int n) { int ch, i=0; // 跳过开头空白字符(可选,不需要可删除) while ((ch = getchar()) != EOF && isspace(ch) && ch != '\n'); if (ch == EOF || ch == '\n') { str[0] = '\0'; return 0; } str[i++] = ch; while ((ch = getchar()) != EOF && ch != '\n') { if (i < n) { str[i++] = ch; } } str[i] = '\0'; // 清空缓冲区中超过长度限制的残留字符 if (ch != EOF && ch != '\n') { while ((ch = getchar()) != EOF && ch != '\n'); } return i; }
修正说明
- 调整计数逻辑:把
num_words++移到循环体内,仅成功读取单词后计数;空输入时释放刚分配的内存,避免内存泄漏。 - 修复qsort参数:确保传入正确的元素大小,让qsort正确处理指针数组。
- 修正循环缩进:给输出循环加上大括号,确保所有输出语句都在循环体内。
- 修复字符串比较函数:正确解引用qsort传入的指针参数,让strcmp比较字符串内容而非地址。
- 完善read_line函数:处理EOF情况、清空残留缓冲区字符,避免后续输入被干扰;可选跳过开头空白字符。
内容的提问来源于stack exchange,提问作者Pepe Cuesta
相关产品推荐
相关产品推荐

