动态分配结构体数组异常:输入乱码与scanf语句跳过问题
问题分析与解决方案
嘿,你的问题根源在于输入缓冲区的残留字符在捣乱,导致fgets和scanf的读取顺序彻底混乱,才会出现随机字符、跳过输入的情况。我给你拆解清楚问题,再提供两种靠谱的修复方案:
核心问题点
- 读取
size后的换行残留:当你用scanf("%d", &size)读完数组大小后,你按下的回车会留在输入流里。接下来第一个fgets会直接读取这个空的换行符,导致members[i].name被设置成空字符串,后续的scanf("%c %d")就会把原本应该是名字的字符错当成rank,自然出现乱码。 %c的读取特性:scanf("%c %d")里的%c会匹配任何字符(包括空格、换行),如果前面的输入残留没清理,很容易读取到非预期的字符,进一步打乱输入流程。
修复方案
方式一:手动清理输入缓冲区
在关键节点清理输入流里的残留换行,确保每个读取函数都能拿到正确的输入:
#include <stdio.h> #include <stdlib.h> #include <string.h> int main() { struct DEP { char name[30]; char rank; int number; }; struct DEP *members; int size, i; scanf("%d", &size); // 吃掉scanf读size后残留的换行符 getchar(); members = malloc(size * sizeof(struct DEP)); if(members == NULL) { return 1; } for(i = 0;i < size;i++) { fgets(members[i].name, 30, stdin); members[i].name[strcspn(members[i].name, "\n")] = '\0'; // %c前加空格,自动跳过所有空白字符(空格、换行、制表符) scanf(" %c %d", &members[i].rank, &members[i].number); // 再次清理scanf后的换行,保证下一轮fgets正常工作 getchar(); printf("%s\n%c\n%d\n", members[i].name, members[i].rank, members[i].number); } free(members); // 别忘了释放动态分配的内存,避免泄漏! return 0; }
方式二:统一用fgets读取(更安全)
避免混用scanf和fgets,统一按行读取输入后再解析,彻底杜绝缓冲区残留问题:
#include <stdio.h> #include <stdlib.h> #include <string.h> int main() { struct DEP { char name[30]; char rank; int number; }; struct DEP *members; int size, i; char buffer[100]; // 临时存储整行输入 // 先读size所在的行,再解析出数字 fgets(buffer, sizeof(buffer), stdin); sscanf(buffer, "%d", &size); members = malloc(size * sizeof(struct DEP)); if(members == NULL) { return 1; } for(i = 0;i < size;i++) { // 读取名字行 fgets(members[i].name, 30, stdin); members[i].name[strcspn(members[i].name, "\n")] = '\0'; // 读取rank和number所在的行,再解析 fgets(buffer, sizeof(buffer), stdin); sscanf(buffer, "%c %d", &members[i].rank, &members[i].number); printf("%s\n%c\n%d\n", members[i].name, members[i].rank, members[i].number); } free(members); return 0; }
测试示例
比如输入:
2 JOHN A 123 MIKE B 456
修复后的代码会正确输出:
JOHN A 123 MIKE B 456
内容的提问来源于stack exchange,提问作者Kritsos




