C语言getchar()、getch()、scanf()对比(附C语言代码)
由于最近收到刚入门c语言
的小朋友关于 “使用scanf()
语句接收char
类型数据时出现了一系列迷惑输出” 的提问, 故重新整理了一下C语言
中关于getchar()
、getch()
、scanf()
三个函数的相关知识点.
[toc]
下面从函数的生命周期理解三个函数
getchar()
当函数开始运行的时候,去stdio
缓冲区看是否有字符,有则获取一个字符,返回给程序,函数结束。
如果stdio
缓冲区为空,则等待从键盘输入数据,同时每输入一个字符都会回显到屏幕上,只有当按下回车键(‘\n’)
,才将按下回车键之前包括回车键的数据存到stdio
缓冲区, 然后getchar()
从stdio
缓冲区获取第一个字符,并返回给程序,同时缓冲区的字符指针往下移动一位(即指针指到已经获取字符的下一个字符),函数结束。(说明:getchar(),可以获取任意字符,包括换行键【ASCII码:10】,空格键【ASCII码:32】等)
代码
#include<stdio.h>
int main(void)
{
int a,b,c;
printf("please input num a:\n");
a=getchar();
printf("please input num b:\n");
b=getchar();
printf("please input num c:\n");
c=getchar();
printf("%d,%d,%d",a,b,c);
}
运行结果
please input num a:
1
please input num b:
please input num c:
2
49,10,50
运行结果解释:
程序运行打印完“please input num a:”
后,进入getchar()
函数,由于此时stdio
缓冲区没有字符,所以程序等待用户从键盘输入;
当输入“1”
并按回车键
后,“1”
和回车键
的ASCII
码存进stdio
缓冲区,然后程序第6行的getchar()
函数获取“1”
存入变量a
中,函数运行结束,继续往下运行.
打印出第7行的输出内容,进入第8行的getchar()
函数,由于此时,stdio
缓冲区还有一个刚才输入的回车键
,getchar()
直接把回车键
的内容取走存入变量b
中.
继续运行程序第9行的打印内容,然后进入第10行的getchar()
函数,此时stdio
缓冲区为空,所以需要等待用户从键盘输入,这里输入“2”
,按下回车键
,getchar()
函数从stdio
缓冲区获取“2"
存入变量c
中.
最后打印结果为”49“
、”10“
、”50“
,分别表示字符”1“
、”回车键“
、”2“
的ASCII
码。
要想达到想要的结果可以这样修改程序,在每次获取字符后多加一个getchar()
,获取stdio
缓冲区中每次输入完字符附加的”回车键“。
改进代码
#include"stdio.h"
int main(void)
{
int a,b,c;
printf("please input num a:\n");
a=getchar();
getchar();
printf("please input num b:\n");
b=getchar();
getchar();
printf("please input num c:\n");
c=getchar();
getchar();
printf("%d,%d,%d\n",a,b,c);
}
运行结果
please input num a:
1
please input num b:
2
please input num c:
3
49,50,51
也可以在每次getchar()
之后加入fflush(stdin)
清空stdio
缓冲区,也可以达到同样的效果。
改进代码
#include"stdio.h"
int main(void)
{
int a,b,c;
printf("please input num a:\n");
a=getchar();
fflush(stdin);
printf("please input num b:\n");
b=getchar();
fflush(stdin);
printf("please input num c:\n");
c=getchar();
fflush(stdin);
printf("%d,%d,%d\n",a,b,c);
}
getch()
getch()
这个函数的直接等待获取从键盘输入的字符,并且不回显在屏幕,并且不用以回车键结尾,没输入完一个按键,程序获取该按键的ASCII
码并返回,该函数就结束。
代码
#include "stdio.h"
#include <conio.h>
int main(void)
{
int a,b,c;
printf("please input num a:\n");
a=getch();
printf("please input num b:\n");
b=getch();
printf("please input num c:\n");
c=getch();
printf("%d,%d,%d\n",a,b,c);
}
运行结果
please input num a:
please input num b:
please input num c:
49,32,50
运行结果解释:
依次输入”1“
、”空格键“
、”2“
结果如上,每次输入的字符不回显在屏幕,不用等待回车键即可获取键盘输入的字符,而是将输入字符的ASCII
码打印出来。
scanf()
scanf()
函数和getchar()
类似,首先从stdio
缓冲区读取字符,如果缓冲区有符合格式要求的数据,则获取数据,返回给程序,函数结束;
如果缓冲区没有符合要求的数据(这里不一定为空,因为有时候缓冲区不为空,但是没有否和格式的数据,例如:缓冲区存在空格
或者回车
,但是返回类型为整型参数),则等待从键盘输入数据,并且必须以回车键
结束,输入的数据存入stdio
缓冲区,(至少输入一个满足格式要求的数据才可以以回车键结束输入,否则按回车键,继续等待输入)然后scnaf()
从缓冲区获取一个数据并返回,函数结束。
代码
#include "stdio.h"
int main(void)
{
int a,b,c;
printf("please input num a:\n");
scanf("%d",&a);
printf("please input num b:\n");
scanf("%d",&b);
printf("please input num c:\n");
scanf("%d",&c);
printf("%d,%d,%d\n",a,b,c);
}
运行结果
please input num a:
1 2
please input num b:
please input num c:
3
1,2,3
运行结果解释:
首先显示程序第5行的打印内容,然后程序执行第6行的scanf()
函数,由于此时stdio
缓冲区为空,所以等待用户从键盘输入;
这里首先输入了一个回车键发现函数并没有结束,继续等待输入,这就说明,在回车键结束输入之前必须至少输入一个满足scanf()
格式要求的数据;
接着输入了几个空格
之后输入”1“
,再输入两个空格
按键之后输入”2“
,然后按回车键
,就可以结束输入;
然后第6行的scanf()
函数获取”1“
存入变量a
中;
接着程序执行第7行的打印内容,发现第8行似乎没有执行,直接打印了第9行的内容,这里其实第8行的scanf()
已经执行,因为此时stdio
缓冲区中还有一个输入的数据”2“
,第8行的scanf()直接从缓冲区读取”2“
存入变量b中,而不需要等待用户从键盘输入;
然后程序就执行了第9行的打印内容,接着执行第10行的scanf()
函数,此时,stdio
没有满足格式的数据,所以需要等待用户从键盘输入,这里先输入了回车键
和几个空格
按键,然后输入”3“
,再输入回车键
. scanf()
获取”3“
,并存入变量c
;
最后打印变量a
,b
,c
的结果,整型形式:1
、2
、3
这里需要指出scanf()
函数在从stdio
缓冲区中取数据的时候,会清除在找到否和格式要求的数据之前的所有字符,其实就是将指针一直移到获取数据的下一位,测试程序如下
代码
#include "stdio.h"
int main(void)
{
int a,b,c;
printf("please input num a:\n");
scanf("%d",&a);
printf("getchar():%d\n",getchar());
printf("please input num b:\n");
scanf("%d",&b);
printf("please input num c:\n");
scanf("%d",&c);
printf("%d,%d,%d",a,b,c);
}
运行结果
please input num a:
1 2
getchar():32
please input num b:
please input num c:
3
1,2,3
运行结果解释:
在前两个scanf()
之间加入了getchar()
,获取的值是32
,即空格
的ASCII
码,所以它获取的是”1“
和”2“
之间输入的空格,而”1“
之前的回车键没有获取到,说明已经被第一个scanf()
函数从stdio
缓冲区取走,或者理解为指针已经指向”1“
之后的地址.
关于
scanf()
获取字符
测试代码
#include "stdio.h"
int main(void)
{
char a,b,c;
printf("please input num a:\n");
scanf("%c",&a);
printf("please input num b:\n");
scanf("%c",&b);
printf("please input num c:\n");
scanf("%c",&c);
printf("%c,%c,%c\n",a,b,c);
}
运行结果
please input num a:
a
please input num b:
please input num c:
b
a,
,b
运行结果解释:
输入a
之后按回车键
,直接运行第7行和第9行的打印内容,似乎第8行没有运行;
这里其实和getchar()
函数一样,在输入a
之后按回车键
,a
和回车键
一起进入stdio
缓冲区;
第6行scanf()
函数从缓冲区获取字符a
存入a
变量,然后执行第7行,第8行执行的时候,因为此时缓冲区有一个回车键
,scanf()
函数获取回车键存入变量b
,所以这里不需要等待用户输入直接进入第9行打印;
之后第10行程序发现缓冲区没有数据,就需要用户输入,这里输入”b“
存入变量c
,然后依次打印变量a
、b
、c
, 可以看出: 先输出”a“
,然后换行,再输出”b“
.
关于改进,同样可以使用getchar()
,获取输入完数据必须输入的回车键
;或者使用fflush(stdin)
清空缓冲区.
小朋友的问题
代码
#include <stdio.h>
// 1,2
// 1.2,3.4
// 666666,888888
// 123,456
// A,a
int main(void)
{
int nA,nB;
float fC,fD;
long lE,lF;
unsigned int u,v;
char ch1,ch2,ch3,ch4,ch5,ch6;
scanf("%d,%d",&nA,&nB);
scanf("%f,%f",&fC,&fD);
scanf("%ld,%ld",&lE,&lF);
scanf("%o,%o",&u,&v);
scanf("%c,%c,%c,%c,%c,%c",&ch1,&ch2,&ch3,&ch4,&ch5,&ch6);
printf("\n");
printf("a=%7d,b=%7d\n",nA,nB);
printf("c=%10.2f,d=%10.2f\n",fC,fD);
printf("e=%17ld,f=%17ld\n",lE,lF);
printf("u=%o,v=%o\n",u,v);
printf("c1=%c,c2=%c,c3=%c,c4=%c,c5=%c,c6=%c\n",ch1,ch2,ch3,ch4,ch5,ch6);
return 0;
}
运行结果
1,2
1.2,3.4
666666,888888
123,456
A,a,B,b,C,c
a= 1,b= 2
c= 1.20,d= 3.40
e= 666666,f= 888888
u=123,v=456
c1=
,c2=,c3=,c4=,c5=,c6=
问题:
为什么程序第24行的关于
ch1,ch2,ch3,ch4,ch5,ch6
的输出不符合预期?问题分析:
程序在执行第17行代码时, 用户在输入
123
,456
之后按回车键
,此时123
,456
和回车键
一起进入stdio
缓冲区;第17行scanf()
函数从缓冲区获取字符123
,456
分别存入u
,v
变量,然后执行第18行代码的时候,因为此时缓冲区有一个回车键
,scanf()
函数获取回车键存入变量ch1
,同时因为读取到回车键
, 导致结束次行代码开始执行后续代码, 所以这里仅获取回车键
存入字符型变量ch1
,而ch2,ch3,ch4,ch5,ch6
未存入任何值.(即为空值)改进建议:
可以使用getchar()
,获取输入完数据必须输入的回车键
.
改进后代码
#include <stdio.h>
int main(void)
{
int nA,nB;
float fC,fD;
long lE,lF;
unsigned int u,v;
char ch1,ch2,ch3,ch4,ch5,ch6;
scanf("%d,%d",&nA,&nB);
scanf("%f,%f",&fC,&fD);
scanf("%ld,%ld",&lE,&lF);
scanf("%o,%o",&u,&v);
getchar();
scanf("%c,%c,%c,%c,%c,%c",&ch1,&ch2,&ch3,&ch4,&ch5,&ch6);
printf("\n");
printf("a=%7d,b=%7d\n",nA,nB);
printf("c=%10.2f,d=%10.2f\n",fC,fD);
printf("e=%17ld,f=%17ld\n",lE,lF);
printf("u=%o,v=%o\n",u,v);
printf("c1=%c,c2=%c,c3=%c,c4=%c,c5=%c,c6=%c\n",ch1,ch2,ch3,ch4,ch5,ch6);
return 0;
}
运行结果
1,2
1.2,3.4
666666,888888
123,456
A,a,B,b,C,c
a= 1,b= 2
c= 1.20,d= 3.40
e= 666666,f= 888888
u=123,v=456
c1=A,c2=a,c3=B,c4=b,c5=C,c6=c
由于本人水平有限,如有理解或描述错误,还请各位批评指正.
邮箱: 517093978@qq.com