📜  后面有fgets() gets() scanf()时,scanf()有问题(1)

📅  最后修改于: 2023-12-03 15:37:10.781000             🧑  作者: Mango

后面有fgets() gets() scanf()时,scanf()有问题

在 C 语言中,我们通常使用输入函数来从用户那里接受输入。其中,fgets()gets()scanf() 是最常用的函数之一。然而,在一些特殊情况下,当我们在一个程序中混合使用这些函数时,会出现一些问题。本文将讨论其中一个常见的问题:当 fgets()gets() 函数在 scanf() 函数之前被调用时,scanf() 函数可能不会如预期工作。

问题描述

考虑下面这段代码:

#include <stdio.h>

int main() {
    char str[100], name[30];
    int age;
    
    printf("Enter your name: ");
    fgets(name, 30, stdin);
    // 或者:
    // gets(name);
    
    printf("Enter your age: ");
    scanf("%d", &age);
    
    printf("Enter a string: ");
    fgets(str, 100, stdin);
    // 或者:
    // gets(str);
    
    printf("Name: %s\n", name);
    printf("Age: %d\n", age);
    printf("String: %s\n", str);
    
    return 0;
}

程序提示用户输入姓名、年龄和字符串,然后将这些值输出到屏幕上。这个程序似乎没有任何问题,但当我们运行程序并尝试输入值时,会发现第二次输入会被跳过。

Enter your name: Alice
Enter your age: 20
Enter a string:

Name: Alice
Age: 20
String:
问题原因

这个问题的原因在于当调用 scanf() 函数后,键盘缓冲区中会有一个换行字符(\n)被留在那里。例如,在上面的程序中,当用户输入年龄时,按下回车键会将 \n 字符留在键盘缓冲区中。

然而,在调用 fgets()gets() 函数时,这个换行符会被读取进来,因此 fgets()gets() 函数会立即返回而不等待用户输入任何值。

解决办法

要解决这个问题,我们可以使用以下两种方法之一:

  1. 在调用 fgets()gets() 函数之后调用 getchar() 函数,将键盘缓冲区中的换行符读取并丢弃。

    printf("Enter your name: ");
    fgets(name, 30, stdin);
    getchar(); // 读取缓冲区中的换行符
    
    printf("Enter your age: ");
    scanf("%d", &age);
    getchar(); // 读取缓冲区中的换行符
    
    printf("Enter a string: ");
    fgets(str, 100, stdin);
    getchar(); // 读取缓冲区中的换行符
    
  2. 使用 scanf() 函数代替 fgets()gets() 函数获取字符串输入。

    printf("Enter your name: ");
    scanf("%29s", name); // 限制最大读入字符数为 29,以避免缓冲区溢出
    
    printf("Enter your age: ");
    scanf("%d", &age);
    
    printf("Enter a string: ");
    scanf("%99s", str); // 限制最大读入字符数为 99,以避免缓冲区溢出
    
结论

在使用 fgets()gets()scanf() 函数时,我们需要注意它们之间的交互作用,特别是输入顺序。为了避免上述问题,我们可以在 fgets()gets() 函数后立即使用 getchar() 函数读取缓冲区中的换行符,或者使用 scanf() 函数代替 fgets()gets() 函数,以避免遗留的换行符导致 scanf() 函数无法如预期工作。