两次使用scanf()函数:在一种情况下有效,而在另一种情况下无效

时间:2019-07-18 14:28:34

标签: c character scanf

我现在正在学习C编程的基础知识,并且正在练习scanf()函数。这个非常非常简单的程序接收一个数字和一个字母,并使用printf()函数显示数字和字母。

如果我要求用户首先输入数字,该程序将起作用,即,要求输入数字,要求输入字母并打印输入。如果我先要求输入字母,程序将要求输入字母,但随后不要求输入数字。

我尝试了多种方法并对它进行重新排序,但似乎不起作用。

这有效:

#include<stdio.h>
 void main(){
    int number;
    char letter;

    printf("Enter letter...");
    scanf("%c", &letter);

    printf("Enter number....");
    scanf("%d", &number);

    printf("Number entered: %d and letter entered: %c.\n", number, letter);
 }

但是,这种组合不起作用:

#include<stdio.h>
void main(){
    int number;
    char letter;

    printf("Enter number....");
    scanf("%d", &number);

    printf("Enter letter...");
    scanf("%c", &letter);

    printf("Number entered: %d and letter entered: %c.\n", number, letter);
 }

我在第一个程序中得到的输出是:

Enter letter...a
Enter number....9
Number entered: 9 and letter entered: a.

哪个正确

但是第二种情况不起作用,我也不知道为什么它不起作用-跳过“输入字母”部分

输出为

Enter number....9
Enter letter...Number entered: 9 and letter entered: 
.

上下文:在上面的示例中,我为字母输入了“ a”,为数字输入了“ 9”。

4 个答案:

答案 0 :(得分:0)

通过以下方式指定scanf

scanf("%c", &letter);

不跳过空格,当用户按Enter键输入以前的数据时,可以读取例如存储在输入缓冲区中的换行符。

改为使用

scanf(" %c", &letter);
       ^^^

跳过空格。

根据C标准(7.21.6.2 fscanf函数)

  

8个输入空格字符(由isspace函数指定)   除非规范中包含[, c 或n指定符。

  

5由空格字符组成的指令由以下命令执行   读取输入内容,直到第一个非空白字符(仍保留   未读),或者直到无法读取更多字符为止。

请注意,根据C标准,不带参数的函数main应该声明为

int main(void)

从C标准(5.1.2.2.1程序启动)

  

1在程序启动时调用的函数称为main。的   实现没有为此函数声明任何原型。应该是   定义为int且没有参数的返回类型:

int main(void) { /* ... */ }

答案 1 :(得分:0)

%c之前添加一个空格。因此,请更改此内容:

scanf("%c", &letter);

对此:

scanf(" %c", &letter);

正如我在caution when using scanf中所写,这将使scanf吃掉空格和特殊字符(否则它将视为输入)。

在这里,它将在输入后消耗换行符,换句话说就是您按的Enter!

确切地说,在您的示例中,请考虑用户(在本例中为您)的操作:

  • 您输入9
  • 您按Enter
  • 您键入“ a”
  • 您按Enter

现在,在这种情况下,当您从键盘上输入某些内容时,它将进入标准输入缓冲区,在那里将耐心等待读取。

在这里,scanf("%d", &number);将会出现并读取一个数字。它会在STDIN缓冲区的第一个单元中找到9,然后对其进行读取,从而将其从缓冲区中删除。

现在,scanf("%c", &letter);到了,它会读取一个字符。它找到换行符,这是您按下的第一个Enter键,该函数现在很高兴-告诉它读取一个字符,这正是它的作用。现在,从缓冲区中删除了换行符(现在剩下的是'a'和换行符-不会读取这两个字符,因为没有其他函数调用了。)

那如果我改写scanf(" %c", &letter);会发生什么变化呢?

第一个scanf仍将读取数字9,并且缓冲区现在将具有换行符,“ a”字符和另一个换行符。

现在调用scanf(“%c”,&letter);`,它将搜索要在STDIN缓冲区中读取的字符,只是现在它会首先使用找到的任何特殊字符。

因此它进入缓冲区,它首先遇到换行符,然后使用它。

然后,它将遇到'a',这不是 特殊字符,因此它将正常读取,并存储到scanf中传递的变量中。

最后一个换行符将保留在STDIN缓冲区中,不被触摸和看不见,直到程序终止并且缓冲区被释放为止。


提示:您可能打算写int main(void)而不是void main()。在What should main() return in C and C++?

中了解更多信息

答案 2 :(得分:0)

事实证明,%d%c之间有惊人的区别。除了%d可能扫描多个数字而%c恰好扫描一个字符这一事实之外,令人惊讶的区别是 %d会跳过任何前导空格,而%c不会

然后,当您使用scanf来读取用户输入时,还有另一个容易忽视的问题,即所有这些新行(\n字符)在插入时会发生什么?用户按下ENTER键输入某些内容?

这就是发生了什么。您的第一个程序有

printf("Enter letter...");
scanf("%c", &letter);

printf("Enter number....");
scanf("%d", &number);

用户键入了一个字母,然后按ENTER,再键入一个数字,然后按ENTER。第一个scanf呼叫未读字母,仅读取其他字母。 \n停留在输入流中。然后,第二个scanf呼叫与%d跳过\n(因为\n是空格)并按照您的需要读取该号码。

但是在您的第二个程序中,输入却以其他顺序排列,如下所示:

printf("Enter number....");
scanf("%d", &number);

printf("Enter letter...");
scanf("%c", &letter);

现在,用户键入一个数字并按ENTER,第一个scanf调用将读取该数字并将\n留在输入流中。但是随后在第二个scanf调用中,%c不会跳过空格,因此读取的“字母”是\n字符。

在这种情况下,解决方案是显式强制执行%c默认不执行的空格跳过。关于scanf的另一个鲜为人知的事实是,格式字符串中的空格并不意味着“完全匹配一个空格字符”,而是“匹配任意数量的空白字符”。因此,如果您将第二个程序更改为:

printf("Enter number....");
scanf("%d", &number);

printf("Enter letter...");
scanf(" %c", &letter);

现在,第二个" %c"调用中scanf中的空格字符将跳过用户键入数字后剩下的\n和第二个{{1} }通话应阅读应有的字母。

最后,进行一些编辑。如果您认为这是一种奇怪的情况,如果您认为scanf的工作方式异常有点奇怪,如果您认为应该很难读懂一个数字后跟一个字母,那么认为我对正在发生的事情的解释比原本应该的要长得多,更复杂-您是对的。 %c是C标准库中较丑陋的功能之一。我不知道有任何C程序员会使用它来做任何事情-我不相信我曾经使用过它。实际上,它的唯一用途是使开始使用C的程序员将数据输入他们的第一个程序,直到他们学习执行该任务的其他更好的方法,而这些方法不涉及scanf

因此,我对您的建议是不要花费太多时间尝试使scanf正常工作或了解其所有其他缺点。 (有很多)。一旦您感到舒适,就开始学习其他更好的输入方法,并将scanf永远留在后面。

答案 3 :(得分:0)

尝试一下

#include <stdio.h>

int main(void) {
    int number;
    char letter;

    printf("Enter letter...");
    scanf("%s", &letter);

    printf("Enter number....");
    scanf("%d", &number);

    printf("Number entered: %d and letter entered: %c.\n", number, letter);
  return 0;
}

如果将%c更改为%s,则会得到正确的输出。