C语言结构体输入异常:使用fgets()仍无法获取首个输入
解决C语言结构体输入时fgets跳过首个字段的问题
这个问题我太熟了——你用scanf输入书籍数量后,第一个fgets直接跳过Titulli的输入,根本不给你输入的机会,直接跳到Autori。本质原因是**scanf("%d", &n)读取完整数后,会把你按下的回车键(换行符\n)留在标准输入缓冲区里**。接下来的fgets一看到缓冲区里的换行符,就误以为你输入了空行,直接把这个换行符读进去了,所以看起来像是跳过了第一个输入项。
快速解决方法
最直接的修复就是在scanf读取数字后,把残留的换行符吃掉,有几种简单的方式:
- 用
getchar()吃掉换行
在scanf("%d", &n);之后加一行:
getchar(); // 把scanf留下的换行符从缓冲区里清掉
这种方法适合你当前的场景,只要用户输入数字后直接回车,就能完美解决。
- 用
scanf的格式字符串自动处理
把读取数字的scanf改成这样:
scanf("%d%*c", &n); // %*c表示读取一个字符但不保存,专门用来吃掉换行
%*c会自动读取紧跟在数字后的换行符,不用额外调用函数。
- 彻底避免
scanf和fgets混用(更推荐)
如果你不想再遇到这类缓冲区问题,可以用fgets读取整行输入,再用sscanf从中提取数字,完全避开scanf的坑:
char input_buf[20]; printf("\n\tShkruani numrine librave qe doni te shtoni: "); fgets(input_buf, sizeof(input_buf), stdin); sscanf(input_buf, "%d", &n);
这样输入缓冲区里不会残留任何多余字符,后续的fgets都能正常工作。
额外的小修复建议
除了核心问题,你的代码还有几个小细节可以优化:
fgets会读取换行符:fgets会把用户输入的回车也存入字符串,后续用puts输出时会多一个空行。可以用strcspn去掉换行符:fgets(libra[nr].titulli, 50, stdin); libra[nr].titulli[strcspn(libra[nr].titulli, "\n")] = '\0'; // 替换换行符为字符串结束符kerko_titulli函数的循环错误:你写的while (fread(...) == 1);后面多了个分号,这会导致循环只是不断读取文件内容,完全不执行后面的判断逻辑。应该把分号去掉,把判断逻辑放到循环体里:nr = 0; while (fread( &libra[nr], sizeof(struct liber), 1, flib) == 1) { if (strcmp(v_autori, libra[nr].autori) == 0) { // 输出书籍信息的代码 } nr++; }main函数的输入类型问题:你用char z;但用scanf("%d", &z)读取整数,这会导致类型不匹配。如果要支持输入数字选项和e退出,应该改成:char z; do { menu(); scanf(" %c", &z); // 前面的空格用来跳过空白字符(比如换行) if (z == '1') shtoliber(); else if (z == '2') kerko_titulli(); } while (z != 'e' && z != 'E' && z != 27);
修改后的核心函数示例
这里给你改好的shtoliber函数,解决了输入问题还处理了换行符:
void shtoliber() { int i, n = 0; FILE * flib; flib = fopen("libra.dat", "wb"); if (flib == NULL) { printf("\nGabim ne hapjen e file!!"); getch(); exit(1); } printf("\n\tShkruani numrine librave qe doni te shtoni: "); scanf("%d", &n); getchar(); // 清理输入缓冲区的换行符 for (i = 0; i < n; i++) { printf("\nTitulli: "); fgets(libra[nr].titulli, 50, stdin); libra[nr].titulli[strcspn(libra[nr].titulli, "\n")] = '\0'; printf("\nAutori: "); fgets(libra[nr].autori, 20, stdin); libra[nr].autori[strcspn(libra[nr].autori, "\n")] = '\0'; printf("\nKategoria: "); fgets(libra[nr].kategoria, 20, stdin); libra[nr].kategoria[strcspn(libra[nr].kategoria, "\n")] = '\0'; printf("\nID: "); fgets(libra[nr].id, 10, stdin); libra[nr].id[strcspn(libra[nr].id, "\n")] = '\0'; printf("\nKopje: "); scanf("%d", &libra[nr].kopje); getchar(); // 清理输入Kopje后的换行符,避免下一次循环出问题 printf("\n*****************\n"); fwrite( &libra[nr], sizeof(struct liber), 1, flib); printf("\nLibri u regjistrua.\n\v"); nr++; } fclose(flib); }
内容的提问来源于stack exchange,提问作者s.dokaj
相关产品推荐
相关产品推荐

