前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >最通俗易懂地讲解scanf、gets和getchar的区别

最通俗易懂地讲解scanf、gets和getchar的区别

作者头像
我是管小亮
发布2020-04-20 17:09:05
4.7K0
发布2020-04-20 17:09:05
举报

文章首发于本人CSDN账号:https://blog.csdn.net/tefuirnever

由于微信不允许外部链接,你需要点击页尾左下角的“阅读原文”,才能访问文中的链接。

1、简介

1、scanf(%c)

首先要说的是 scanf,它是格式输入函数,标准格式如下:

代码语言:javascript
复制
int scanf(const char * restrict format,...);

标准输入流(stdin) 中按照说明的格式读入多个字符,并存入 ==以输入参数的值为地址的变量== 中,所以必须得有 &,除了把字符串读入字符数组中。

为啥?

很简单,因为数组变量名称本身就是特殊的指针,即,数组首元素的地址,故无需使用 & 取地址,完事。

举个例子:

代码语言:javascript
复制
char a[10];
scanf("%s",a);

没有 & 地址符,程序正常运行。


scanf 在遇到 空格符回车符(\n)制表符(\t) 时,都会认为本次输入结束,所有它不能接收 空格符 还有 回车符(\n),那么它是如何处理 回车符(\n) 的呢?

除了一种特殊情况:scanf() 会忽略行开头的所有 空格!!!

scanf末尾回车符 的处理是把 回车符(\n) 保留在缓存中。

代码语言:javascript
复制
#include<stdio.h>
int main(){
	char a,ch;
	int count=0;
	while(1){
		scanf("%c",&a);
		count++;
		printf("**************\n");
		printf("%d\n",count);
	}

	return 0;
}

首先输入 a,然后 回车,因为scanf末尾回车符 的处理是把 回车符(\n) 保留在缓存中,所以除了 a 之外,还有 回车 也被读进来了,即,每次蹦两个数字。

这一点和 gets 是不同的!!!在后面的 gets 中会有详细地介绍。

小结

不接收 空格,不接收 回车

2、getchar

接着要说的,是 getchar() 函数。

它的作用是从键盘获取且只能获取一个字符。

定义如下:

代码语言:javascript
复制
int getchar(void)

getchar() 函数是可以接收 空格 的,但是不能接收 回车。即最后的 回车符 也不会被接收,getchar() 是会舍弃最后的 回车符 的。

回车 是干啥用的呢?

因为 getchar 函数只能输入字符型,所以在输入时遇到 回车键(\n) 才从缓冲区依次提取字符,遇到 空格符不会结束,而是会接收它!!!

下面来看一个例子:

代码语言:javascript
复制
#include<stdio.h>
int main(){
	char a,ch;
	int count=0;
	while((ch=getchar())!='q'){
		count++;
		printf("**************\n");
		printf("%d\n",count);
	}

	return 0;
}

首先确定的一件事是,getchar 是不接收 回车 的,所以正常情况下的计数应该是1。

也同样是因为它本身只能接收1个字符,所以这个 回车 被留在缓存流中了,而我们这里的程序是遇到 q 才停止,故而程序又循环了一下,相当于输入了一个 回车!!!

如果稍微修改一下程序为:

代码语言:javascript
复制
#include<stdio.h>
int main(){
	char a,ch;
	int count=0;
	while((ch=getchar())!='\n'){
		count++;
		printf("**************\n");
		printf("%d\n",count);
	}

	return 0;
}

可以看到程序只运行了一次就停止了,因为 回车 是留在缓存流中的,默认输入了。

小结

接收 空格,不接收 回车

3、实例

总结一下两个函数的使用:

==输入完成后:==

  • ==scanf 把数据一把全梭了;==
  • ==getchar 把数据一个一个从兜里掏。==

在很多时候会出现这样一种情况,即先输入了一个 scanf 的语句,然后可能要用到 gets ,这个时候上一个 scanf 留下的 回车 就会打搅乱下面的数据读取!!!这个时候就需要加一个 回车符(\n),用 scanf('\n);;或者读取这个 回车符(\n),用 gets();getchar();

比如最近在做PTA上的C语言题库时发现的一个题:

给定 n 本书的名称和定价,本题要求编写程序,查找并输出其中定价最高和最低的书的名称和定价。

代码语言:javascript
复制
#include<stdio.h>
struct book{
    char name[31];
    double price;
};
int main(){
    struct book a[10];
	int i;
	double max=-1,min=10000;
	int flag1=0,flag2=0;
	int n;
    scanf("%d",&n);
    for(i=0;i<n;++i){
	  	scanf("\n");	// 去除回车
	  	//gets();
	  	//getchar();
        gets(a[i].name);
    	scanf("%lf",&a[i].price);
    	if(max<a[i].price){
    		max=a[i].price;
    		flag1=i;
		}
		if(min>a[i].price){
			min=a[i].price;
			flag2=i;
		}
	}
	printf("%.2lf, %s\n",a[flag1].price,a[flag1].name);
    printf("%.2lf, %s\n",a[flag2].price,a[flag2].name);

    return 0;
}

首先使用 scanf 输入的书的数量3,留下了一个 回车,如果在这里直接接着使用一个 scanf 的话,就会出错:

因为 回车 会留在缓存流中,并被下一个函数 get 读取到,从而扰乱了本来的数据读取,继而出现了非预期结果。

小结

一定要注意 scanf回车符!!!

2、字符串

1、scanf(%s)

%c%s 的区别是一个是字符,一个是字符串,从这里可以看得出,scanf 函数能对各种类型进行输入,

而不仅仅局限于字符或是字符串,而字符是 getchar,字符串是 gets

不过,无论是对待字符还是字符串,scanf 的处理都是比较相似的,这一点倒是比较容易学习和使用,但是 来自 pudn,只有一段开头话

  • 中文版本:在数据大量的情况下,用 gets 读取快于 scanf() 10倍以上。
  • 英文版本:A large number of cases in the data, using gets read faster than scanf 10 times.

小结

不接收 空格回车

2、gets

到这里,你应该不会忘记上面说过的 scanf 是如何处理 回车符(\n) 的了,这一点和 gets 是差别巨大的!!!

gets 对末尾 回车符 的处理方式是,接收 回车,但把 回车 替换为 \0,不像 scanf 是留在缓存中,所以在用 gets 时,要注意数组的大小增加1,不然就会出现数组越界等问题。

还是看个例子,还是上面那个题,虽然题中说的是不超过30个字符,但是因为还有一个 回车符 转换成的 空字符,所以数组大小需要加1!!!


除了 回车 就是 空格 的问题了,gets 是接收 空格 的,也就是可以读取并输出 空格

终止的标志是 Enter 结束输入(空格不结束),比如这里的 HelloWorld 之间的空格就是正常的。

代码语言:javascript
复制
#include<stdio.h>
#include<string.h>
int main(){
    char a[100];
    gets(a);
    int i;
	for(i=0;i<strlen(a);i++){
		printf("%c",a[i]);
	}

    return 0;
}

如果换成 scanf 的话,就只能读取一半了,因为空格也是它的终止符!

代码语言:javascript
复制
#include<stdio.h>
#include<string.h>
int main(){
    char a[100];
    int i;
    scanf("%s",&a);
	for(i=0;i<strlen(a);i++){
		printf("%c",a[i]);
	}

    return 0;
}

小结

接收 空格回车

3、实例

最直接的方式进行对比就是求一下字符串的长度。

代码语言:javascript
复制
#include<stdio.h>
#include<string.h>
int main(){
    char a[100];
    gets(a);
    printf("%d",strlen(a));

    return 0;
}

代码语言:javascript
复制
#include<stdio.h>
#include<string.h>
int main(){
    char a[100];
//    gets(a);
	scanf("%s",&a);
    printf("%d",strlen(a));

    return 0;
}

这也就解释了为什么前面要用 gets 或者是 getchar 去去除 回车

3、总结

  • scanf 忽略行开头的所有空格,并以各种格式化进行数据输入,直到遇到 空格回车 结束输入,不接收 空格回车,留在缓存区中;
  • getchar 只读取一个字符,包括 空格 但是不包括 回车回车 会留在缓冲区中;
  • gets 读取以任何字符开头的字符串,读取的字符串包括 空格 但是不包括 回车,以 回车 结束输入,接收 空格回车,但之后会丢弃 回车 并以 \0 代替;

最后的一个图给出常用的 while 表达形式:

参考文章

  • https://zhidao.baidu.com/question/63301588.html
  • https://www.php.cn/faq/415503.html
  • https://www.runoob.com/cprogramming/c-tutorial.html
  • https://www.cnblogs.com/hlongch/p/5742477.html
本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2020-03-14,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 程序员管小亮 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 1、scanf(%c)
  • 2、getchar
  • 3、实例
  • 1、scanf(%s)
  • 2、gets
  • 3、实例
  • 参考文章
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档