本文参考C Primerf Plus进行C语言学习
文章目录
- 使用scanf()
- 从scanf()角度看输入
- 格式字符串中的普通字符
- scanf()的返回值
1.使用scanf()
- 如果用scanf()读取基本变量类型的值,在变量名前加上一个&;
- 如果用scanf()把字符串读入字符数组中,不要使用&。
#include<stdio.h>
int main(void)
{
int age; //变量
float assets; //变量
char pet[30]; //字符数组,用于储存字符串
printf("Enter your age,assets,and favourite pet.\n");
scanf("%d %f",&age,&assets); //这里要使用&
scanf("%s",pet); //字符数组不使用&
printf("%d $%.2 %s\n",age,assets,pet);
return 0;
}
运行结果:
只要在每个输入项之间输入至少一个换行符、空格或制表符即可。
唯一 例外的是%c转换说明。根据%c,scanf()会读取每个字符,包括空白。
scanf()和printf()函数所用的转换说明与printf()函数几乎相同。主要区别是,float类型和double类型,printf()都使用%f、%e、%E、%g和%G转换说明。而scanf()只把它们用于float类型,对于double类型要使用1修饰符。
转换说明 | 含义 |
%c | 把输入解释成字符 |
%d | 把输入解释成有符号十进制整数 |
%e、%f、%g、%a | 把输入解释成浮点数(C99标准新增了%a) |
%E、%F、%G、%A | 把输入解释成浮点数(C99标准新增了%A) |
%i | 把输入解释成有符号十进制整数 |
%o | 把输入解释成有符号八进制整数 |
%p | 把输入解释成指针(地址) |
%s | 把输入解释成字符串。从第1个非空白字符开始,到下一个空白字符之前的所有字符都是输入 |
%u | 把输入解释成无符号十进制整数 |
%x、%X | 把输入解释成有符号十六进制整数 |
转换说明 | 含义 |
* | 抑制赋值(详见后面解释) 示例:"%*d" |
数字 | 最大字段宽度。输入达到最大字段宽度处,或第1次遇到空白字符时停止 示例:"%10s" |
hh | 把整数作为signed char或unsigned char类型读取 示例:"%hhd"、"%hhu" |
11 | 把整数作为long long或unsigned long long 类型读取(C99) 示例:"%lld"、"%llu" |
h、1或L | "%hd"和”%hi”表明把对应的值储存为short int类型 "%ho"、"%hx"和"%hu"表明把对应的值储存为unsigned shot int 类型 号“%1d"和"%1i"表明把对应的值储存为long类型 "%1o"、"%1x"和"%1u"表明把对应的值储存为unsigned long 类型 "%1f"、"%1e"和"%1g"表明把对应的值储存为double类型 在 e、f 和g前面使用 L而不是1,表明把对应的值被储存为long double 类型。如果没有修饰符,d、i、o和x表明对应的值被储存为int 类型,f和g表明把的值储存为float 类型 |
j | 在整型转换说明后面时,表明使用intmax_t或uintmax_t类型(C99) 示例:"%zd"、"%zo" |
z | 在整型转换说明后面时,表明使用sizeof的返回类型(C99) |
t | 在整型转换说明后面时,表明使用表示两个指针差值的类型(C99 )示例:"%td"、"%tx" |
如你所见,使用转换说明比较复杂,而且这些表中还省略了一些特性。省略的主要特性是,从高贸式化源中读取选定数据,如穿孔卡或其他数据记录。因为在本书中,scanf()主要作为与程序交互的便工具,所以我们不在书中讨论更复杂的特性。
1.从scanf()角度看输入
接下来,我们更详细地研究scanf()怎样读取输入。假设scanf()根据一个%d转换说明读取一个整数scanf()函数每次读取一个字符,跳过所有的空白字符,直至遇到第1个非空白字符才开始读取。因为要取整数,所以scanf()希望发现一个数字字符或者一个符号(+或-)。如果找到一个数字或符号,它便保存该字符,并读取下一个字符。如果下一个字符是数字,它便保存该数字并读取下一个字符。scanf()不断地读取和保存字符,直至遇到非数字字符。如果遇到一个非数字字符,它便认为读到了整数的末尾。然后,scant把非数字字符放回输入。这意味着程序在下一次读取输入时,首先读到的是上一次读取丢弃的非数字字符,最后,scanf()计算已读取数字(可能还有符号)相应的数值,并将计算后的值放入指定的变量中。
如果使用字段宽度,scanf()会在字段结尾或第1个空白字符处停止读取(满足两个条件之一便停止)。
如果第1个非空白字符是A而不是数字,会发生什么情况?scanf()将停在那里,并把A放回输入中,不会把值赋给指定变量。程序在下一次读取输入时,首先读到的字符是A。如果程序只使用gd转换说明,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()函数。
2.格式字符串中的普通字符
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个非空白字符开始读取。
3.scanf()的返回值
scanf()函数返回成功读取的项数。如果没有读取任何项,且需要读取一个数字而用户却输入一个非数值字符串,scanf()便返回0。当scanf()检测到“文件结尾”时,会返回EOF(EOF是stdio.h中定义的特殊值,通常用#define 指令把EOF 定义为-1)。在读者学会if语句和while语句后,便可使用scanf()的返回值来检测和处理不匹配的输入。