printf,puts,scanf,gets 的浅薄见解(C语言)

要了解printf,puts,scanf,gets要先了解一下以下概念:

  格式控制字符串:以%开头的字符串,在%后面跟有各种格式字符,以说明输入输出数据的类型、形式、长度、小数位等。

        例如:printf("i=%d",i) 语句中的 %d 就是格式控制字符串。

  非格式控制字符串:原样输出,在显示中起提提示作用。

        例如:printf("i=%d",i) 语句中的 i= 就是非格式控制字符串。

  空白字符:空格、回车、Tab键三种不会显示出来的字符。

  缓冲区:缓冲区的具体概念读者可以自己去找资料看(可惜我还看不太懂),我这里用一种浅薄的方式说一下,缓冲区就像一个直线型的中介,我们从键盘输入的任何东西(包括空白字符)都是先从左往右依次存入缓冲区再被输入函数从左往右依次读取的,缓冲区就是暂时存储我们从键盘输入的东西并供输入函数(scanf,gets)读取的中介区域。

  输入输出原则:原输入输出表列中给出了各个输入输出项,要求格式控制字符串和各输入输出项在数量和类型上应该一一对应。通俗点就是引号内有几个 %d 这样的格式控制字符串,引号后面就要有几个输入输出项与之对应。


printf:

        原封不动输出引号内的非格式控制字符串并将格式控制字符串会转换成对应的量,就这么简单明了,具体细节用法有很多大佬介绍,就不细说了。

puts:

        输出字符串,并将字符串的终结符'\0'转换为换行符'\n'。只能输出字符串,不能输出数值或者进行格式转换,即不能要求输出格式增加空格、换行(指的是输出内容的中间进行换行)等要求。

scanf:

        从缓冲区开头往后读取内容,忽略前导的空白字符,直到遇到有效内容后的空白字符结束。

        前导就是最前面的意思,前导的空白字符指的就是在变量或者常量等有效内容前面的空白字符,缓冲区的开头如果有空白字符那么这些空白字符就叫做前导的空白字符。

        举个荔枝:

#include<stdio.h>
int main()
{
	int a;
	scanf("%d",&a);
	printf("%d",a);
	return 0;
}

        然后用户从键盘输入"空格回车空格回车2空格回车",那么缓冲区就是"空格回车空格回车2空格回车",scanf在从缓冲区读入时第一个读到的是空格,按理来说scanf读到空格就会结束,但scanf很有个性,不想无功而返,所以忽略(准确来说是忽略并将其从缓冲区丢掉,后面的忽略均为此意)了2前面的空格和回车,读到了2,然后又遇到了空格,已经读到2了,所以就心满意足的结束了,所以说会忽略前导的空白字符。

         但是,有的读者可能会发现,在输入2后输入空格没有反应,只有按回车才能输出,其实这也是回车的神奇之处,首先scanf在读入2后面的空格后就结束了,但是scanf结束后程序会一直停滞在那一步不往下面走,这个时候就需要回车来告诉程序应该往下走了,所以按回车后程序就会从scanf那步往下走,这样就会输出了。

        scanf是输入函数,所以一般引号内最好只有格式控制字符串,否则你需要重新输入一遍多余的非格式控制字符串,很繁琐。

        举个荔枝:

#include<stdio.h>
int main()
{
	int a;
	scanf("a=%d",&a);
	printf("a=%d",a);
	return 0;
}

        这个代码在输入的时候如果我们只输入2,就达不到我们的目的,因为 a=%d 和 2 是不匹配的,所以我们需要从键盘输入 a=2 与 a=%d 对应,由此可见这样是很繁琐的,所以才有了前面一番话。

scanf输入多个值的问题:

#include<stdio.h>
int main()
{
	int a,b,c;
	scanf("%d %d %d",&a,&b,&c);
	printf("a=%d,b=%d,c=%d",a,b,c);
	return 0;
}

        这是我们平常输入输出三个数的代码,当然你也可以不在 %d 之间加空格,但你有思考过 %d 中间的空格是否会影响scanf输入吗?答案肯定是不会的,可是为什么呢,scanf遇空格不会结束吗?莫急,待我慢慢道来。

        我们要清楚scanf读入多个变量的逻辑,读到第一个 %d 时开始在缓冲区找第一个有效内容(读入有效内容后该有效内容就不存在于缓冲区了,已经从缓冲区读取出来了),然后再往后读入,读到第二个 %d时 会再次在缓冲区找有效内容,然后再读入第三个%d,再在缓冲区找有效内容,然后结束。唉?那不是忽略了两个 %d 之间的空格吗?没错,就是忽略了,其实只要不是末尾的空白字符scanf都不会理(后面马上讲),不相信可以自己试一下下面的代码:

#include<stdio.h>
int main()
{
	int a,b,c;
	scanf("  \n%d\n		\n 	%d  %d",&a,&b,&c);
	printf("a=%d,b=%d,c=%d",a,b,c);
	return 0;
}

        运行后发现scanf忽略了这些空白字符,所以scanf已经傲娇到连自己引号里的空白字符都忽略了。 但是,从键盘输入数据时,给多个变量赋的值之间一定要用空格、回车、Tab 键隔开,用以区分是给不同变量赋的值,也是结束本次 %d 的读入,进入下一个 %d 的读入,而且空格、回车或、Tab 键的数量不限(反正scanf不理),只要有就行(用来表示该个%d的读入结束),一般都使用一个空格。

scanf("%d \n    ",&a)(末尾空白字符)问题:

#include<stdio.h>
int main()
{
	int a;
	scanf("%d \n",&a);
	printf("a=%d",a);
	return 0;
}

        运行后,你会发现,为什么回车按到底也不会输出,不管是空格回车还是Tab键都没有输出,直到你在输入一个数字,唉?这又是什么鬼啊!少年,且听我慢慢道来。

        在末尾的空白字符因为天天被忽略也有了脾气,它们会欺骗scanf说后面还有输入,然后scanf 就会傻傻地等你的输入,而你却输入了空格回车这些空白字符,scanf直接忽略掉了,认为这些空白字符是两个输入之间的空白字符,所以你也不理解为什么它还不输出,它也不理解你为什么还不给他有效内容,所以,懂了吧,只要你再随便输入 一个有效内容,哪怕是一个字母、一个标点符号、一个括号都可以、然后回车,就会有输出了,并且回车后scanf发现自己被骗了,根本没有与你后面输入的字母、标点符号、括号等内容匹配的项,一气之下就不想要这些字母、标点符号、括号等内容了,把这些内容留在缓冲区了,等后面的输入函数来读取。由此可见,末尾的空白字符真的很烦人啊,作为诚实的中国人,最好不要让scanf末尾有空白字符。

scanf读入字符串问题:

        忽略前导空白字符,将缓冲区的字符串保存到字符数组,直到遇到有效内容后的空白字符,并自动在字符串后面加终结符 '\0',在遇到回车后进入下一步,但这个回车会被保留在缓存区内,等待其他的输入函数将它读入。

        当然,如果你不想scanf因为读到空格结束,你想让它也能读入空格进字符串数组,可以使用scanf("%[^\n]",s) 语句只有遇到回车才会结束。

gets:

        将缓冲区的内容以字符串的形式存储在字符数组中,直至遇到回车换行符,但是回车换行符 '\n' 不作为字符数组的有效字符,而是转换为字符串终结符 '\0',使用gets时,系统会将最后输入的换行符从缓冲区中取出来,然后丢弃,所以缓冲区中不会遗留换行符。

scanf与gets连用的问题:

#include<stdio.h>
int main()
{
	char a[1000]={0},b[1000]={0};
	scanf("%s",a);
	gets(b);
	printf("a=%s,b=%s",a,b);
	return 0;
}

        此代码运行时,为了输入美观,在输入第一个字符串后我们会想回车换行,在第二行输入另一个字符串,但当我们按下回车后,程序就直接结束了,就离谱,这是scanf和gets连用的陷阱。scanf在读入回车后结束了并往下走,但并不会把回车拿出去丢掉,而是会将其保留在缓冲区,这时候gets一进去就遇到了回车,将 '\n' 转换成 '\0' 后就结束了,什么都没捞到,所以输出时字符数组b为空。

        解决办法

1,在%s后加上一个空白字符(原理和末尾空白字符一样),即scanf("%s\n",a),这种写法也叫作scanf吃掉回车符。

2,将gets放在scanf前面,因为gets会丢掉回车换行符。

3,用两次scanf,即scanf("%s%s",a,b),即使输入第一个字符串后回车,scanf读第二个字符串是会忽略前导的回车(也就是输入第一个字符串后按的回车),直接读取后面的字符串。

4,在scanf后面放一句 getchar() 语句,因为getchar只会读取一个字符,所以刚好可以把回车换行符给吃掉。 


以上就是我对printf,puts,scanf,gets的一些浅薄见解,希望对你有所帮助!                                  

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值