我现在正在学习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”。
答案 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!
确切地说,在您的示例中,请考虑用户(在本例中为您)的操作:
现在,在这种情况下,当您从键盘上输入某些内容时,它将进入标准输入缓冲区,在那里将耐心等待读取。
在这里,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
,则会得到正确的输出。