You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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.

问题原因

  1. 输入缓冲区残留换行符:使用scanf("%d", ...)读取学号、分数时,只会提取数字,输入结束时按下的回车(\n)会留在输入缓冲区中。下一次循环调用gets()时,它会直接读取这个换行符,认为姓名输入已完成,因此跳过手动输入步骤。
  2. 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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.06 02:05:18