Q1:关于EOF
如果输入hello回车,输出结果如下:
此时再输入ctrl+D(即linux下的EOF表示),程序结束。如果输入hello之后不输入回车,而是EOF,此时程序并没有结束,而是可以继续输入,但并不换行。若再直接ctrl+D那么程序结束。
这说明,当getchar()读取到换行符的时候,认为此次输入结束。程序换行,执行putchar()输出刚才输入的内容。如果不以回车,而以EOF作为结尾,getchar()仍然并且只是认为此次输入结束,而不是结束程序。当EOF单独出现的时候,getchar()才认为是输入行为终止。
Q2:getchar()获取几个字符?如何执行的?
在上面的例子中,输入hello,输出hello。那程序执行的过程是不是getchar()获取到了hello,将其赋给c,判断c!=EOF,输出c?看下面这个例子
还用'hello'作为例子,当我们输入hello回车时,程序输出h,然后结束。很显然,getchar()只获取到了一个字符。
当把注释去掉,再次执行程序。输入hello回车,输出he。程序中出现了两次getchar(),但整个过程中只有一次键盘输入过程,也即第一次getchar(),第二次getchar()并没有要求终端输入。看来,将getchar()理解为请求终端获取输入也不完全正确。其实getchar()的执行的原理是这样的(有部分个人理解):
用键盘输入字符的时候,输入的字符被放入了缓冲区,直到用户按下回车结束本次输入(回车符也被放入缓冲区)。其实getchar()是从输入流缓冲区中读取数据的,如果缓冲区中没有数据,则会进入等待,直到缓冲区有数据。这也就是程序执行到第一个getchar()时会等待用户输入的原因。当缓冲区有数据时,getchar()会从缓冲区获取第一个字符(显然,缓冲区是FIFO的),在例子中就是h,putchar(c)输出h,再次执行getchar(),获取到了e,putchar(c)输出e,程序结束。
当然,假设只输入一个字符'a'的时候,也只需要一次键盘输入,程序就会结束。因为回车也算作一个字符,所以输入的其实是两个字符。直接输入回车的话,就需要输入两次才能结束程序。
最后再看一个例子证明一下上面的判断:
输入hello,输出104 101。这两个数字也正是h和e的ascii码。
Q3:关于getch()
getch()和getchar()类似,也是获取一个字符。 不同的是getch()不从缓冲区获取,而是直接从键盘输入获取,也即输入一个字符,立刻返回一个字符,不需要按回车。
Q4:关于scanf()
scanf()类似getchar(),略有不同的是结束标志。看下面的例子:
输入hello world,发现只需要一次输入,程序会输出两次,然后结束。scanf()与getchar()一样,也是从输入流缓冲区获取数据,不同的是,scanf()获取数据时如果 遇到回车、空格或TAB则会停止 ,一次获取数据过程结束。第二个scanf()会继续从输入流缓冲区获取数据。
在Q1中,如果输入hello回车,仔细观察的话会发现,输出也是hello回车,说明getchar()也获取了缓冲区的回车符。如果在上面这个例子中输入hello回车,输出也是hello回车,并且程序没有结束而是继续等待用户输入,这说明第二个scanf()从缓冲区获取不到数据了,然后等待用户输入,输入world回车,输出world,程序结束。即下面的结果:
首先说明, scanf()丢弃了输入hello后的那个回车符,也即scanf()读取字符串会丢弃结尾的回车符。 从这个例子中也可以看出,输入hello回车,输出也是hello回车,但是printf()中有一个\n换行符,如果scanf()能获取到hello后面的回车的话,输出结果应该下面这个样子的:
这也说明了scanf()会丢弃字符串结尾的回车符。 但注意,回车符并没有被scanf()跳过而残留在缓冲区内,而是被scanf()获取但是丢弃了,此时缓冲区内的回车符已经不存在了。
Q5:关于gets()
gets和scanf()的用法类似,但是gets()可以获取带空格的字符串,看这个例子:
输入hello world,输出hello world,并继续等待用户输入,输入helloTABworld,输出helloTABworld(TAB代表键盘的tab键,输入制表符),程序结束。
gets()并不会因为字符串中有空格或者TAB而结束字符的获取,但和scanf()一样,会忽略字符串结尾的回车符。
清除缓冲区内的残留数据
1、利用函数fflush(stdin)
注意:ANSI C中并没有将这个函数作为标准的一部分,是编译器支持的,并不是所有编译器都支持这个函数。所以,严格的讲,这样并不具备绝对的可移植性。
2、手动取出缓冲区里的残留数据
scanf("%[^\n]",str);
- #include <stdio.h>
- int main() {
- int c;
- while((c = getchar()) != EOF)
- putchar(c);
- return 0;
- }
如果输入hello回车,输出结果如下:
- hello
- hello
此时再输入ctrl+D(即linux下的EOF表示),程序结束。如果输入hello之后不输入回车,而是EOF,此时程序并没有结束,而是可以继续输入,但并不换行。若再直接ctrl+D那么程序结束。
这说明,当getchar()读取到换行符的时候,认为此次输入结束。程序换行,执行putchar()输出刚才输入的内容。如果不以回车,而以EOF作为结尾,getchar()仍然并且只是认为此次输入结束,而不是结束程序。当EOF单独出现的时候,getchar()才认为是输入行为终止。
Q2:getchar()获取几个字符?如何执行的?
在上面的例子中,输入hello,输出hello。那程序执行的过程是不是getchar()获取到了hello,将其赋给c,判断c!=EOF,输出c?看下面这个例子
- #include <stdio.h>
- int main() {
- int c;
- c = getchar();
- putchar(c);
- /*
- c = getchar();
- putchar(c);
- */
- return 0;
- }
还用'hello'作为例子,当我们输入hello回车时,程序输出h,然后结束。很显然,getchar()只获取到了一个字符。
当把注释去掉,再次执行程序。输入hello回车,输出he。程序中出现了两次getchar(),但整个过程中只有一次键盘输入过程,也即第一次getchar(),第二次getchar()并没有要求终端输入。看来,将getchar()理解为请求终端获取输入也不完全正确。其实getchar()的执行的原理是这样的(有部分个人理解):
用键盘输入字符的时候,输入的字符被放入了缓冲区,直到用户按下回车结束本次输入(回车符也被放入缓冲区)。其实getchar()是从输入流缓冲区中读取数据的,如果缓冲区中没有数据,则会进入等待,直到缓冲区有数据。这也就是程序执行到第一个getchar()时会等待用户输入的原因。当缓冲区有数据时,getchar()会从缓冲区获取第一个字符(显然,缓冲区是FIFO的),在例子中就是h,putchar(c)输出h,再次执行getchar(),获取到了e,putchar(c)输出e,程序结束。
当然,假设只输入一个字符'a'的时候,也只需要一次键盘输入,程序就会结束。因为回车也算作一个字符,所以输入的其实是两个字符。直接输入回车的话,就需要输入两次才能结束程序。
最后再看一个例子证明一下上面的判断:
- #include <stdio.h>
- int main() {
- int ch1, ch2;
- ch1 = getchar();
- ch2 = getchar();
- printf("%d %d", ch1, ch2);
- return 0;
- }
输入hello,输出104 101。这两个数字也正是h和e的ascii码。
Q3:关于getch()
getch()和getchar()类似,也是获取一个字符。 不同的是getch()不从缓冲区获取,而是直接从键盘输入获取,也即输入一个字符,立刻返回一个字符,不需要按回车。
Q4:关于scanf()
scanf()类似getchar(),略有不同的是结束标志。看下面的例子:
- #include <stdio.h>
- int main() {
- char chs1[10], chs2[10];
- scanf("%s", chs1);
- printf("%s\n", chs1);
- scanf("%s", chs2);
- printf("%s\n", chs2);
- return 0;
- }
输入hello world,发现只需要一次输入,程序会输出两次,然后结束。scanf()与getchar()一样,也是从输入流缓冲区获取数据,不同的是,scanf()获取数据时如果 遇到回车、空格或TAB则会停止 ,一次获取数据过程结束。第二个scanf()会继续从输入流缓冲区获取数据。
在Q1中,如果输入hello回车,仔细观察的话会发现,输出也是hello回车,说明getchar()也获取了缓冲区的回车符。如果在上面这个例子中输入hello回车,输出也是hello回车,并且程序没有结束而是继续等待用户输入,这说明第二个scanf()从缓冲区获取不到数据了,然后等待用户输入,输入world回车,输出world,程序结束。即下面的结果:
- hello
- hello
- world
- world
首先说明, scanf()丢弃了输入hello后的那个回车符,也即scanf()读取字符串会丢弃结尾的回车符。 从这个例子中也可以看出,输入hello回车,输出也是hello回车,但是printf()中有一个\n换行符,如果scanf()能获取到hello后面的回车的话,输出结果应该下面这个样子的:
- hello
- hello
- world
- world
这也说明了scanf()会丢弃字符串结尾的回车符。 但注意,回车符并没有被scanf()跳过而残留在缓冲区内,而是被scanf()获取但是丢弃了,此时缓冲区内的回车符已经不存在了。
Q5:关于gets()
gets和scanf()的用法类似,但是gets()可以获取带空格的字符串,看这个例子:
- #include <stdio.h>
- int main() {
- char chs1[10], chs2[10];
- gets(chs1);
- printf("%s\n", chs1);
- gets(chs2);
- printf("%s\n", chs2);
- return 0;
- }
输入hello world,输出hello world,并继续等待用户输入,输入helloTABworld,输出helloTABworld(TAB代表键盘的tab键,输入制表符),程序结束。
- hello world
- hello world
- hello world
- hello world
gets()并不会因为字符串中有空格或者TAB而结束字符的获取,但和scanf()一样,会忽略字符串结尾的回车符。
清除缓冲区内的残留数据
1、利用函数fflush(stdin)
注意:ANSI C中并没有将这个函数作为标准的一部分,是编译器支持的,并不是所有编译器都支持这个函数。所以,严格的讲,这样并不具备绝对的可移植性。
2、手动取出缓冲区里的残留数据
scanf("%[^\n]",str);