【C语言】最通俗易懂地讲解scanf、gets和getchar的区别(相信我,看了一定懂!!!)

专栏C++学习笔记

声明

1)本文仅供学术交流,非商用。所以部分参考资料并没有详细对应。如果某部分不小心侵犯了大家的利益,还望海涵,并联系博主删除。
2)博主才疏学浅,文中如有不当之处,请各位指出,共同进步,谢谢。
3)此属于第一版本,若有错误,还需继续修正与增删。还望大家多多指点。大家都共享一点点,一起为祖国科研的推进添砖加瓦。

〇、写在前面

在这里插入图片描述
最近认真钻研了一下,scanfgetsgetchar 的区别,发现好多写的博客都很凌乱,看了半天不知所云为何物,决定自己写一个博客记录总结一下。

一、字符

在这里插入图片描述

1、scanf(%c)

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

int scanf(const char * restrict format,...);

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

为啥?

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

举个例子:
在这里插入图片描述

char a[10];
scanf("%s",a);

在这里插入图片描述
没有 & 地址符,程序正常运行。
在这里插入图片描述


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

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

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

#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() 函数。

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

定义如下:

int getchar(void)

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

回车 是干啥用的呢?

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

下面来看一个例子:

#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 才停止,故而程序又循环了一下,相当于输入了一个 回车!!!

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

#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 本书的名称和定价,本题要求编写程序,查找并输出其中定价最高和最低的书的名称和定价。
在这里插入图片描述

#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回车符!!!

二、字符串

在这里插入图片描述

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 之间的空格就是正常的。

#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 的话,就只能读取一半了,因为空格也是它的终止符!

#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、实例

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

#include<stdio.h>
#include<string.h>
int main(){
    char a[100];
    gets(a);
    printf("%d",strlen(a));
    
    return 0;
}

在这里插入图片描述


#include<stdio.h>
#include<string.h>
int main(){
    char a[100];
//    gets(a);
	scanf("%s",&a);
    printf("%d",strlen(a));
    
    return 0;
}

在这里插入图片描述

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

三、总结

在这里插入图片描述

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

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

在这里插入图片描述
在这里插入图片描述

如果想要更多的资源,欢迎关注 @我是管小亮,文字强迫症MAX~

回复【福利】即可获取我为你准备的大礼,包括C++,编程四大件,NLP,深度学习等等的资料。

想看更多文(段)章(子),欢迎关注微信公众号「程序员管小亮」~

在这里插入图片描述

参考文章

  • 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 CSDN 皮肤主题: 酷酷鲨 设计师:CSDN官方博客 返回首页