C语言中 scanf() 和 fgets() 的问题

5

我想读取用户输入并将其作为包括空格在内的字符串存储。我搜索了解决方案,被指向使用fgets()或scanf(%[^\n], str)。但是这两种方法都给我一个错误。

这是我的代码:

//MAX_CHARACTERS is set to 30

 scanf("%d", &input);
 if (input == 1){
        int pr;
        char na[MAX_CHARACTERS+1];
        printf("\nEnter the name: ");
        scanf("%[^\t\n]", &na);
        while (strlen(na)>MAX_CHARACTERS){
            printf("\nName is too long, enter new name: ");
            scanf("%[^\t\n]", &na);
        }// end na check
        printf("\nEnter priority: ");
        scanf("%d", &pr);
        while (pr>MAX_PRIORITY || pr <MIN_PRIORITY){
            printf("\nBad priority, enter new priority (0-100): ");
            scanf("%d", &pr);
        }//end pr check

如果我在所有的%[^\t\n]实例中使用%s,那么它可以正常工作,但是当我使用%[^\t\n]fgets(na, 30, stdin)时,它会跳过第一个输入名字的scanf()直接到"Enter priority:"。然后当我打印时,我的名字被留空,带着我输入的优先级。编辑:对不起,第一个scanf()缺少引号是个错别字,不是问题的原因。我为第一个scanf("%d", input)输入了'1'。修复了它。由于我还不能发表回答,有人找出了问题所在。如果还有人感兴趣,问题是第一个scanf()。
scanf("%d", &input);

这段代码在缓存中留下了一个换行符“\n”。第二个代码将读取该换行符作为输入,因此它被跳过了。

解决方案:

添加一个

fflush(stdin); //right after the if statement seems to have fixed the issue. 

感谢大家的帮助。

你在第一个scanf中缺少引号。是打字错误吗? - Dave
你在第一个scanf(即“&input”)中输入什么?是“1ENTER”还是“1corilENTER”? :) - pmg
我不太理解scanf,但是如果要读取一个字符串,你的参数应该是一个char*,即na&na[0]。但是我没有看到任何%s格式说明符。 - Kerrek SB
你可不可以把你的“解决方案部分”放在答案里面,而不是问题里面? - Paŭlo Ebermann
6
“fflush(stdin);” 不是解决方案。在输入流上使用“fflush()”的行为是未定义的。如果你在输入缓冲区中留下了字符,你需要读取它们。一个更通用的解决方案是使用“fgets()”将一行文本读入字符串,然后在字符串上使用“sscanf()”提取数据。(“sscanf()”在数字输入方面可能存在问题,但这可以留到以后再讨论。) - Keith Thompson
1
不要忘记检查 scanf()sscanf() 返回的值。 (如果输入不是数字,那么 (scanf("%d", &input); 会发生什么,请三思。) - Keith Thompson
4个回答

7
这是使用scanf()获取用户输入的问题,它不适用于处理字符串或任何错误输入。 scanf()是用来读取格式化输入(例如具有严格和特定格式的文件)。当从用户处获取输入时,输入可能是格式错误的,从而导致问题。您应该使用fgets()来读取输入并自行解析。
为什么第二个scanf()调用被跳过呢?因为第一个调用只消耗输入的数字。但是,按下Enter键后的换行符仍留在输入缓冲区中,并成为第二个调用的输入。要解决此问题,您需要从输入缓冲区中删除该换行符。最安全的方法是使用getchar(),直到读取到换行符,然后继续执行程序。避免使用fflush(stdin)模式,这样做不安全,可能会引起更多问题。
下面是一个简单的函数,可用于读取字符,直到读取到换行符:
void clear_newlines(void)
{
    int c;
    do
    {
        c = getchar();
    } while (c != '\n' && c != EOF);
}

在处理非字符串数据时,请在任何对scanf()的调用之后调用此函数。

2
    scanf("%d",&choice);
    fgetc(stdin);

我读取了stdin中的fgetc,这样就会保留'\n'字符,所以你的缓冲区就变得清晰明了。

0

代码的第一行:

scanf(%d, &input);

应该是:

scanf("%d", &input);

即缺少引号


0
scanf("%[^\t\n]", &na);

应该是:

scanf("%[^\t\n]", na);

例如,删除&

fgets应该可以正常工作,除了它会包括用户按下回车键时的换行符。您需要将其去掉。


当我移除 & 符号时,它仍然跳过第一个 scanf("%[^\n]", na)。 - coril

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接