按学生姓氏字母序排序数组的C代码输入输出异常排查
问题分析与修复:无法输入多个学生姓名及排序异常的C代码问题
一、输入异常的核心原因
fflush(stdin)是未定义行为
C标准明确规定fflush只能用来刷新输出流的缓冲区,对输入流调用它属于错误操作,不同编译器的处理逻辑完全不一致。这会导致输入完学生数量n后,缓冲区里残留的换行符没被正确清理,后续输入函数要么读到空内容,要么直接打乱整个输入流程。gets()函数不安全且已被废弃gets()完全不检查输入长度,当你输入像"Nihan ahmed"这种超过8个字符的名字时,会直接溢出你定义的name[10][8]缓冲区,破坏程序的内存结构,导致程序异常卡死,没法继续接收下一个名字。而且这个函数在C11标准里已经被彻底移除了,绝对不要使用它。数组存储空间严重不足
你定义的每个学生名字数组只有8个字节,去掉字符串终止符\0,最多只能存7个字符,显然不够存储带空格的全名,这也是缓冲区溢出的直接诱因。
二、排序逻辑的致命问题
寻找空格的循环逻辑错误
你的代码里k初始为0,先执行++k再判断是否为空格,这直接跳过了名字的第一个字符。如果遇到没有空格的名字,这个循环会无限执行,越界访问数组内存,触发不可预测的未定义行为。排序逻辑不完整且错误
你只实现了冒泡排序的皮毛,没有多轮遍历完成完整排序;而且只比较了空格后的第一个字符,没有完整比较姓氏的字典序,最终的排序结果肯定不符合预期。
三、修正后的可运行代码
#include<stdio.h> #include<stdlib.h> #include<string.h> int main() { // 增大数组大小,足够存储常见的全名 char name[10][50], temp[50]; int i, j, n; printf("Enter the number of students:\n"); // 用scanf读取n后,手动清理缓冲区的换行符 scanf("%d", &n); // 跳过输入缓冲区里的换行和空白字符 while(getchar() != '\n'); printf("\nPlease enter the names of the students:\n"); for(i = 0; i < n; i++) { // 用fgets代替gets,安全且能读取带空格的字符串 fgets(name[i], sizeof(name[i]), stdin); // 去掉fgets读取到的换行符 name[i][strcspn(name[i], "\n")] = '\0'; } // 冒泡排序:按姓氏(空格后的部分)排序,没有空格则按全名排序 for(i = 0; i < n - 1; i++) { for(j = i + 1; j < n; j++) { // 找到每个名字里空格的位置 char *lastNameI = strchr(name[i], ' '); char *lastNameJ = strchr(name[j], ' '); // 如果有空格,用姓氏比较;否则用全名比较 const char *cmpStrI = lastNameI ? lastNameI + 1 : name[i]; const char *cmpStrJ = lastNameJ ? lastNameJ + 1 : name[j]; if(strcmp(cmpStrI, cmpStrJ) > 0) { strcpy(temp, name[i]); strcpy(name[i], name[j]); strcpy(name[j], temp); } } } printf("After sorting the array:\n"); for(i = 0; i < n; i++) { puts(name[i]); } return 0; }
关键修正点说明
- 用
while(getchar() != '\n')代替fflush(stdin),安全清理输入缓冲区的换行符,避免跨编译器的兼容性问题。 - 改用
fgets()读取字符串,自动限制输入长度,避免缓冲区溢出,同时手动去掉读取到的换行符,保证字符串格式正确。 - 增大了名字数组的大小,足够存储带空格的全名。
- 用
strchr()找空格位置,逻辑更简洁安全;用strcmp()完整比较字符串的字典序,实现了正确的冒泡排序逻辑。
内容的提问来源于stack exchange,提问作者user13597809
相关产品推荐
相关产品推荐

