5.2 使用scanf()

C语言学习栏目目录

目录

从scanf()角度看输入

格式字符串中的普通字符

scanf()的返回值


    上篇我们学习了输出(printf()函数),接下来我们转至输入——学习scanf()函数。C库包含了多个输入函数,scanf()是最通用的一个,因为它可以读取不同格式的数据。当然,从键盘输入的都是文本,因为键盘只能生成文本字符:字母、数字和标点符号。如果要输入整数 2014,就要键入字符 2、0、1、4。如果要将其储存为数值而不是字符串,程序就必须把字符依次转换成数值,这就是scanf()要做的。scanf()把输入的字符串转换成整数、浮点数、字符或字符串,而printf()正好与它相反,把整数、浮点数、字符和字符串转换成显示在屏幕上的文本。

    canf()和 printf()类似,也使用格式字符串和参数列表。scanf()中的格式字符串表明字符输入流的目标数据类型。两个函数主要的区别在参数列表中。printf()函数使用变量、常量和表达式,而scanf()函数使用指向变量的指针。这里,读者不必了解如何使用指针,只需记住以下两条简单的规则:

    a、如果用scanf()读取基本变量类型的值,在变量名前加上一个&;

    b、如果用scanf()把字符串读入字符数组中,不要使用&。

下列程序清单中的小程序演示了这两条规则。

/************************************************************************
功能:演示scanf()函数                                                                      
************************************************************************/
#include <stdio.h>
int main(void)
{
	int age;		// 变量
	float assets;		// 变量
	char pet[30];		// 字符数组,用于储存字符串
	printf("输入你年龄, 财产, 和最喜欢的宠物.\n");
	scanf("%d %f", &age, &assets);		// 这里要使用&
	scanf("%s", pet);		// 字符数组不使用&
	printf("%d   $%.2f元   %s\n", age, assets, pet);
	system("pause");
	return 0;
}

下面是该程序与用户交互的示例:(如果Vs编译器报错参考这个:VS2015使用scanf报错解决方案,我是使用方法5)

输入你年龄, 财产, 和最喜欢的宠物.
30
250猫
30   $250.00元   猫
请按任意键继续. . .

scanf()函数使用空白(换行符、制表符和空格)把输入分成多个字段。在依次把转换说明和字段匹配时跳过空白。注意,上面示例的输入项(粗体部分是用户的输入)分成了两行。只要在每个输入项之间输入至少一个换行符、空格或制表符即可,可以在一行或多行输入:

输入你年龄, 财产, 和最喜欢的宠物.
30
250
猫
30   $250.00元   猫
请按任意键继续. . .

唯一例外的是%c转换说明。根据%c,scanf()会读取每个字符,包括空白。我们稍后详述这部分。scanf()函数所用的转换说明与printf()函数几乎相同。主要的区别是,对于float类型和double类型,printf()都使用%f、%e、%E、%g和%G转换说明。而scanf()只把它们用于float类型,对于double类型时要使用l修饰符。下表列出了C99标准中常用的转换说明。

转换说明符及其输出结果
转换说明符输出
%a浮点数,十六进制数和p-计数法(C90)
%A浮点数,十六进制数和p-计数法(C90)
%c一个字符
%d有符号十进制整数
%e浮点数,e-计数法
%E浮点数,E-计数法
%f浮点数,十进制计数法
%g根据数值不同自动选择%f或%e. %e格式在指数小于-4或大于等于精度时使用
%G根据数值不同自动选择%f或%E. %E格式在指数小于-4或大于等于精度时使用
%i有符号十进制整数(与%d相同)
%o无符号八进制整数
%p指针
%s字符串
%u无符号十进制整数
%x使用十六进制数字0f的无符号十六进制整数
%X使用十六进制数字0F的无符号十六进制整数
%%百分号
转换修饰符
修饰符意义
标志

五种标志(-, +, 空格, #, 0), 可以使用零到多个标志

例如: "%-10d"

digit(s)

字段宽度的最小值.如果该字段不能容纳要打印的数或字符串,系统会使用更宽的字段

例如: "%4d" 最小占用4个字段宽度

.digit(s)

精度.对于%e, %E和%f转换,表示将要在小数点右边打印的数字的位数.

对于%g和%G转换,是有效数字的最大位数.

对于%s转换,表示将要打印的字符的最大数目.

对于整数转换,表示将要打印的数字的最小位数,如果必要,要使用前导零来达到这个位数.

只要使用".",表示其后跟一个零,所以%.f与%.0f相同.

例如: "%5.2f" 表示一个浮点数,它的字段宽度为5,小数点后有两个数字

h

和整数转换说明符一起使用,表示一个 short int 或 unsigned short int 类型数值

例如: "%hu", "%hx", "%6.4hd"

hh

和整数转换说明符一起使用,表示一个 signed char 或 unsigned char 类型值

例如: "%hhu", "%hhx", "%6.4hhd"

j

和整数转换说明符一起使用,表示一个 intmax_t 或 uintmax_t 值

例如: "%jd", "%8jX"

l

和整数转换说明符一起使用,表示一个 long int 或 unsigned long int 类型值

例如: "%ld", "%8lu"

ll

和整数转换说明符一起使用,表示一个 long long int 或 unsigned long long int 类型值(C99)

例如: "%lld", "%8llu"

L

和浮点数转换说明符一起使用,表示一个 long double 类型值

例如: "%Lf", "%10.4Le"

t

和整数转换说明符一起使用,表示一个 ptrdiff_t 值(与两个指针之间的差相对应的类型)(C99)

例如: "%td", "%12ti"

z

和整数转换说明符一起使用,表示一个 size_t 值(sizeof返回的类型)(C99)

例如: "%zd", "%12zx"

转换修饰标志
标志意义
-

项目左对齐.即把项目打印在字段的左侧开始处

例如: "%-20s"

+

有符号的值若为正,则显示加号;若为负,则显示减号

例如: "%+6.2f"

空格

有符号的值若为正,则显示带前导空格(不显示符号);若为负,则显示减号

+表示会覆盖空格标志

例如: "% 6.2f"

#

使用转换说明符的可选形式.若为%o格式,则以0开始;

若为%x或%X格式,则以0x或0X开始.

对于所有的浮点形式,#保证了即使不跟任何数字,也打印一个小数点字符.

对于%g或%G格式,#防止尾随零被删除.

例如: "%#o", "%#8.0f", "%+#10.3E"

0

对于所有的数字格式,用前导零而不是用空格填充字段宽度.

如果出现-标志或者指定了精度(对于整数)则忽略该标志.

例如: "%010d", "%08.3f"

从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字符串。实际上,在C语言中scanf()并不是最常用的输入函数。这里重点介绍它是因为它能读取不同类型的数据。C 语言还有其他的输入函数,如 getchar()和 fgets()。这两个函数更适合处理一些特殊情况,如读取单个字符或包含空格的字符串。我们将在后续文章中讨论这些函数。目前,无论程序中需要读取整数、小数、字符还是字符串,都可以使用scanf()函数。

格式字符串中的普通字符

scanf()函数允许把普通字符放在格式字符串中。除空格字符外的普通字符必须与输入字符串严格匹配。例如,假设在两个转换说明中添加一个逗号:

scanf("%d,%d", &n, &m);

scanf()函数将其解释成:用户将输入一个数字、一个逗号,然后再输入一个数字。也就是说,用户必须像下面这样进行输入两个整数:

88,121

由于格式字符串中,%d后面紧跟逗号,所以必须在输入88后再输入一个逗号。但是,由于scanf()会跳过整数前面的空白,所以下面两种输入方式都可以:

88, 121
和
88,
121

格式字符串中的空白意味着跳过下一个输入项前面的所有空白。例如,对于下面的语句:

scanf("%d ,%d", &n, &m);

以下的输入格式都没问题:

88,121
88 ,121
88 , 121
请注意,“所有空白”的概念包括没有空格的特殊情况。

除了%c,其他转换说明都会自动跳过待输入值前面所有的空白。因此,scanf("%d%d", &n, &m)与scanf("%d %d", &n, &m)的行为相同。对
于%c,在格式字符串中添加一个空格字符会有所不同。例如,如果把%c放在格式字符串中的空格前面,scanf()便会跳过空格,从第1个非空白字符开始读取。也就是说,scanf("%c",  &ch)从输入中的第1个字符开始读取,而scanf(" %c", &ch)则从第1个非空白字符开始读取。

scanf()的返回值

scanf()函数返回成功读取的项数。如果没有读取任何项,且需要读取一个数字而用户却输入一个非数值字符串,scanf()便返回0。当scanf()检测到“文件结尾”时,会返回EOF(EOF是stdio.h中定义的特殊值,通常用#define指令把EOF定义为-1)。我们将在第6章中讨论文件结尾的相关内容以及如何利用scanf()的返回值。在读者学会if语句和while语句后,便可使用scanf()的返回值来检测和处理不匹配的输入。

 

源码下载

 

 

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

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

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值