scanf()函数格式字符串普通字符与转换说明输入分析

(来源 C Primer Plus page221)
一、从scanf()角度看输入
接下来,我们更详细地研究scanf()怎样读取输入。假设scanf()根据一个%d转换说明读取一个整数。scanf()函数每次读取一个字符,跳过所有的空白字符,直至遇到第1个非空白字符才开始读取。因为要读取整数,所以scanf()希望发现一个数字字符或者一个符号(+或-)。如果找到一个数字或符号,它便保存该字符,并读取下一个字符。如果下一个字符是数字,它便保存该数字并读取下一个字符。scanf()不断地读取和保存字符,直至遇到非数字字符。如果遇到一个非数字字符,它便认为读到了整数的末尾。然后,scanf()把非数字字符放回输入。这意味着程序在下一次读取输入时,首先读到的是上一次读取丢弃的非数字字符。最后,scanf()计算已读取数字(可能还有符号)相应的数值,并将计算后的值放入指定的变量中。
如果使用字段宽度,scanf()会在字段结尾或第1个空白字符处停止读取(满足两个条件之一便停止)。
如果第1个非空白字符是A而不是数字,会发生什么情况?scanf()将停在那里,并把A放回输入中,不会把值赋给指定变量。程序在下一次读取输入时,首先读到的字符是A。如果程序只使用%d转换说明, scanf()就一直无法越过A读下一个字符。另外,如果使用带多个转换说明的scanf(),C规定在第1个出错处停止读取输入。
用其他数值匹配的转换说明读取输入和用%d 的情况相同。区别在于scanf()会把更多字符识别成数字的一部分。例如,%x转换说明要求scanf()识别十六进制数a~f和A~F。浮点转换说明要求scanf()识别小数点、e记数法(指数记数法)和新增的p记数法(十六进制指数记数法)。
如果使用%s 转换说明,scanf()会读取除空白以外的所有字符。scanf()跳过空白开始读取第 1 个非空白字符,并保存非空白字符直到再次遇到空白。这意味着 scanf()根据%s 转换说明读取一个单词,即不包含空白字符的字符串。如果使用字段宽度,scanf()在字段末尾或第1个空白字符处停止读取。无法利用字段宽度让只有一个%s的scanf()读取多个单词。最后要注意一点:当scanf()把字符串放进指定数组中时,它会在字符序列的末尾加上’\0’,让数组中的内容成为一个C字符串。

scanf()函数使用空白(换行符、制表符和空格)把输入分成多个字段。在依次把转换说明和字段匹配时跳过空白。
除了%c,其他转换说明都会自动跳过待输入值前面所有的空白。

#include <stdio.h>
int main(void)
{
	int age; // 变量
	float assets; // 变量
	char pet[30]; // 字符数组,用于储存字符串
	printf("Enter your age, assets, and favorite pet.\n");
	scanf("%d %f", &age, &assets); // 这里要使用&
	scanf("%s", pet); // 字符数组不使用&
	printf("%d $%.2f %s\n", age, assets, pet);
	getchar();/*方便看结果,根据需要调节数量*/
	getchar();
	getchar();
	return 0;
}
/*格式字符串两数据间使用空格或者使用多个scanf()函数分别输入数据时,输入形式较自由,可以
随意使用空白。scanf()函数使用空白(换行符、制表符和空格)把输入分成多个字段。在依次把转
换说明和字段匹配时跳过空白。
vs2017输入输出结果:
Enter your age, assets, and favorite pet.
  18
 89640.763
	 panda
18 $89640.77 panda
*/

/*数据不匹配时输出结果,程序只读取了Panda这个输入
vs2017输入输出结果:
Enter your age, assets, and favorite pet.
Panda 18  5634.12
-858993460 $-107374176.00 Panda
*/

二、格式字符串中的普通字符
scanf()函数允许把普通字符放在格式字符串中。除空格字符外的普通字符必须与输入字符串严格匹配。
1、scanf()中除c%外的其它转换说明
两数据之间只有空格:(输入方式自由,可随意使用空白)

#include <stdio.h>
int main(void)
{
	int n, m;		
	scanf("%d %d",&n,&m);/*注意在两个输入数据之间使用空格,在输入数据时较自由,可以
	在两个数据之间使用任意数量的空白(换行符、制表符和空格)*/
	printf("**%d**%d**\n",n,m);
	getchar();/*方便看结果,根据需求选择数量*/
	getchar();
	return 0;
}
/*vs2017输入输出结果:
   78

 89
**78**89**
*/

两数据之间只有逗号:(逗号必须紧跟第一个数据)与逗号之后第二个数据之前有空格结果相同

#include <stdio.h>
int main(void)
{
	int n, m;
	printf("0123456789\n");
	scanf("%d,%d", &n, &m);/*两数据之间只有逗号*/
	printf("**%d**%d**\n", n, m);
	getchar();/*方便看结果,根据需求选择数量*/
	getchar();
	getchar();
	return 0;
}
/*逗号与第一个数据之间没空格。
vs2017输入输出结果:
0123456789
 32,
	  56
**32**56**
*/

/*逗号与第一个数据之间有空格,输出错误
vs2017输入输出结果:
0123456789
32 ,  56
**32**-858993460**
*/

逗号之前有空格:
a.逗号之前第一个数据之后有空格

#include <stdio.h>
int main(void)
{
	int n, m;
	printf("0123456789\n");
	scanf("%d ,%d", &n, &m);/*第一个数据之后逗号之前有空格*/
	printf("**%d**%d**\n", n, m);
	getchar();/*方便看结果,根据需求选择数量*/
	getchar();
	getchar();
	return 0;
}
/*数据之间没空格。
vs2017输入输出结果:
0123456789
  32,56
**32**56**
*/

/*数据与逗号之间有空格
vs2017输入输出结果:
0123456789
  32  , 56
**32**56**

0123456789
 32   ,
   56
**32**56**
*/

b.第一个数据之前有空格(结果与两数据之间只有逗号相同)

#include <stdio.h>
int main(void)
{
	int n, m;
	printf("0123456789\n");
	scanf(" %d,%d", &n, &m);/*第一个转换说明之前有空格*/
	printf("**%d**%d**\n", n, m);
	getchar();/*方便看结果,根据需求选择数量*/
	getchar();
	getchar();
	return 0;
}
/*数据之间没空格。
vs2017输入输出结果:
0123456789
32,56
**32**56**
*/

/*逗号紧跟第一个数据
vs2017输入输出结果:
0123456789
 32,
	 56
**32**56**
*/

/*逗号与第一个数据之间有空格,输出出错
vs2017输入输出结果:
0123456789
32  ,  56
**32**-858993460**
*/

普通字符之间有空格是否输入自由:
a.普通字符之间没空格:

#include <stdio.h>
int main(void)
{
	int n, m;
	printf("0123456789\n");
	scanf("%d,,%d", &n, &m);/*两逗号之间没空格*/
	printf("**%d**%d**\n", n, m);
	getchar();/*方便看结果,根据需求选择数量*/
	getchar();
	getchar();
	return 0;
}
/*数据之间没空格。
vs2017输入输出结果:
0123456789
 23,,56
**23**56**
*/

/*逗号之间有空格,输出出错
vs2017输入输出结果:
0123456789
23, ,56
**23**-858993460**
*/

b.普通字符之间有空格

#include <stdio.h>
int main(void)
{
	int n, m;
	printf("0123456789\n");
	scanf("%d, ,%d", &n, &m);/*两逗号之间有空格*/
	printf("**%d**%d**\n", n, m);
	getchar();/*方便看结果,根据需求选择数量*/
	getchar();
	getchar();
	return 0;
}
/*逗号之间没空格。
vs2017输入输出结果:
0123456789
23,,56
**23**56**
*/

/*逗号之间有空格
vs2017输入输出结果:
0123456789
 23,
	  ,
   56
**23**56**
*/

空白(换行符、制表符和空格)
小节总结:格式字符串中不带c%这个转换说明,除空格外的普通字符其前一个字符是空格,则其输入自由(其前可随意使用空白);除空格外的普通字符其前一个字符不是空格,则其输入要严格按照格式;除c%外的转换说明输入自由(其前可随意使用空白)。

2、scanf()带有%c这个转换说明
c%前有空格(一个转换说明前有空格)

#include <stdio.h>
int main(void)
{
	char n, m;
	printf("0123456789\n");
	scanf("%c %c",&n,&m);/*两转换说明之间有空格*/
	printf("**%c**%c**\n",n,m);
	getchar();/*方便看结果,根据需求选择数量*/
	getchar();
	getchar();
	return 0;
}
/*a、b之间有一个空格
vs2017输入输出结果:
0123456789
a b
**a**b**
*/

/*转换说明之前有空格,输入自由(可使用空白)
vs2017输入输出结果:
0123456789
a
	 b
**a**b**
*/

/*先读取了一个空格给n,因为第二个转换说明前有空格,跳过其它空白(换行符、制表符和空格)取a给m。
vs2017输入输出结果:
0123456789


	 a  b
** **a**
*/

c%前有空格(两个转换说明前都有空格)(可以自由使用空白)

#include <stdio.h>
int main(void)
{
	char n, m;
	printf("0123456789\n");
	scanf(" %c %c",&n,&m);/*两转换说明之前都有空格*/
	printf("**%c**%c**\n",n,m);
	getchar();/*方便看结果,根据需求选择数量*/
	getchar();
	getchar();
	return 0;
}
/*ab可以自由输入
vs2017输入输出结果:
0123456789
	a
  b
**a**b**
*/

格式字符串带有除空格外的其它普通字符

#include <stdio.h>
int main(void)
{
	char n, m;
	printf("0123456789\n");
	scanf(" %c ,%c",&n,&m);/*第一个转换说明之前有空格,第二个转换说明前只有逗号,逗号与第一个转换说明之间有空格*/
	printf("**%c**%c**\n",n,m);
	getchar();/*方便看结果,根据需求选择数量*/
	getchar();
	getchar();
	return 0;
}
/*逗号和b紧挨着
vs2017输入输出结果:
0123456789
   a
	 ,b
**a**b**
*/

/*逗号和b之间有空格。第一个转换说明前有空格,跳过一些空白,取a给n;逗号与第一个转换说明
之间有空格,因此其输入自由(其前可用空白);第二个转换说明与逗号之间没空格,因此取紧挨逗
号的空格给m。
vs2017输入输出结果:
0123456789
   a
  ,   b
**a** **
*/

空白(换行符、制表符和空格)
小节总结:格式字符串中带有c%这个转换说明,c%前一个字符是空格,其输入自由(其前可随意使用空白);c%前一个字符不是空格,其输入要严格按照格式;除空格外的普通字符前一个字符是空格,其输入自由(其前可随意使用空白);除空格外的普通字符前一个字符不是空格,其输入要严格按照格式。

混合输入测试:

#include <stdio.h>
int main(void)
{
	char n, m;
	char p[30],q[30];
	int i;
	float j;
	scanf(" %c , %c", &n, &m);
	scanf("%s ,%s", p, q);
	scanf("%d, , ,%f", &i, &j);/*第一个逗号前一个字符不是空格,输入要严格按照规则(即逗号要紧跟数据之后输入)*/
	printf("**%c**%c**\n", n, m);
	printf("**%s**%s**\n", p,q);
	printf("**%d**%f**\n", i, j);
	getchar();/*方便看结果,根据需求选择数量*/
	getchar();
	getchar();
	return 0;
}
/*
vs2017输入输出结果:
  a   ,
   b
   panda    ,
    apple
  36,   ,   ,
   560.4
**a**b**
**panda**apple**
**36**560.400024**
*/

全篇总结:scanf()函数格式字符串中,除空格外的普通字符和c%这个转换说明输入规则相同,其前一个字符是空格,则其输入自由(其前可随意使用空白),其前一个字符不是空格,则其输入要严格按照格式;除c%外的转换说明输入自由(其前可随意使用空白)。

  • 1
    点赞
  • 5
    收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
©️2022 CSDN 皮肤主题:数字20 设计师:CSDN官方博客 返回首页
评论

打赏作者

新手上路记录

你的鼓励将是我创作的最大动力

¥2 ¥4 ¥6 ¥10 ¥20
输入1-500的整数
余额支付 (余额:-- )
扫码支付
扫码支付:¥2
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值