C语言中gets()函数异常:循环读取结构体姓名仅首次有效
C语言输入姓名时跳过问题解决
问题描述
定义了student结构体,尝试用gets()函数获取学生姓名,第一次循环能正常工作,但后续迭代直接跳过姓名输入,无法获取有效内容。以下是相关代码及运行输出:
代码示例
#include <stdio.h> struct student{ int rollno; char name[15]; struct { int sub1; int sub2; int sub3; }marks; }fs[3]; int main(){ int marks, sub1, sub2, sub3, x, y, count; struct student temp; for (x=0; x<3; x++){ printf("\nEnter details of the student %d:\n", x+1); printf("Please Enter your name: "); gets(fs[x].name); printf("Please Enter your roll no: "); scanf("%d", &fs[x].rollno); printf("Please Enter your marks for sub 1: "); scanf("%d", &fs[x].marks.sub1); printf("Please Enter your marks for sub 2: "); scanf("%d", &fs[x].marks.sub2); printf("Please Enter your marks for sub 3: "); scanf("%d", &fs[x].marks.sub3); } }
运行输出
Enter details of the student 1: Please Enter your name: Louis Please Enter your roll no: 12 Please Enter your marks for sub 1: 87 Please Enter your marks for sub 2: 79 Please Enter your marks for sub 3: 83 Enter details of the student 2: Please Enter your name: Please Enter your roll no: 4 Please Enter your marks for sub 1: 5 Please Enter your marks for sub 2: 3 Please Enter your marks for sub 3: 2 Enter details of the student 3: Please Enter your name: Please Enter your roll no: 54 Please Enter your marks for sub 1: 32 Please Enter your marks for sub 2: 45 Please Enter your marks for sub 3: 34 Total & Average of each student.
问题原因
- 输入缓冲区残留换行符:使用
scanf("%d", ...)读取学号、分数时,只会提取数字,输入结束时按下的回车(\n)会留在输入缓冲区中。下一次循环调用gets()时,它会直接读取这个换行符,认为姓名输入已完成,因此跳过手动输入步骤。 gets()本身不安全:该函数不检查输入长度,若输入的姓名超过name[15]的容量,会导致缓冲区溢出,C11标准已正式废弃此函数。
新手友好的替代输入方案
方案1:用scanf读取无空格姓名
scanf("%s", ...)会自动跳过空白字符(包括换行符),适合读取不带空格的姓名,用法简单:
printf("Please Enter your name: "); scanf("%s", fs[x].name); // 替换原有的gets()
方案2:用fgets读取带空格姓名(推荐)
fgets是gets的安全替代,能限制读取长度,避免缓冲区溢出。需要先清除缓冲区残留的换行符:
for (x=0; x<3; x++){ printf("\nEnter details of the student %d:\n", x+1); printf("Please Enter your name: "); // 第一次循环缓冲区为空,无需清除;后续循环清除残留换行 if (x != 0) { getchar(); } // 读取姓名,限制长度为数组大小 fgets(fs[x].name, sizeof(fs[x].name), stdin); // 去掉fgets读取到的换行符 fs[x].name[strcspn(fs[x].name, "\n")] = '\0'; // 后续的scanf代码保持不变 printf("Please Enter your roll no: "); scanf("%d", &fs[x].rollno); printf("Please Enter your marks for sub 1: "); scanf("%d", &fs[x].marks.sub1); printf("Please Enter your marks for sub 2: "); scanf("%d", &fs[x].marks.sub2); printf("Please Enter your marks for sub 3: "); scanf("%d", &fs[x].marks.sub3); }
strcspn函数会找到换行符的位置,将其替换为字符串结束符\0,避免姓名中包含换行。
方案3:用scanf读取带空格姓名
通过%[^\n]格式符可以读取所有字符直到换行,前面加空格跳过残留空白:
printf("Please Enter your name: "); // 限制读取14个字符,留一个位置给字符串结束符 scanf(" %14[^\n]", fs[x].name);
内容的提问来源于stack exchange,提问作者Zeus Legend
相关产品推荐
相关产品推荐

