直接摘抄《C Primer Plus》算求,太经典了,我再偷把懒,就当复习了~
一、概述
从键盘输入的是文本,因为那些键生成文本字符: 字母、数字和标点。比如说,当您想输入整数2004时,您键入字符2、 0、 0和 4 ,如果想把它们存储成4个数值而非字符串,那么您的程序必须把这个字符串逐个字符地转换成数值,这就是scanf()所做的工作!它把输入的字符串转换成各种形式:整数、浮点数、字符和 C的字符串。它是 printf()的逆操作,后者把整数、浮点数、字符和 C的字符串转换成要在屏幕上显示的文本。
跟 printf ( )一样, scanf ( )使用控制字符串和参数列表。控制字符串指出输入将被转换成的格式。主要的区别是在参数列表中。printf()函数使用变量名、常量和表达式,而 scanf()函数使用指向变量的指针。幸运的是,要使用该函数,不必对指针有任何了解,只需要记住下面这些简单规则:
·如果使用 scanf()来读取前面讨论过的某种基本变量类型的值,请在变量名之前加上一个&。
·如果使用 scanf()把一个字符串读进一个字符数组中,请不要使用&。
scanf()函数使用空格(换行、制表符和空格)来决定怎样把输入分成几个字段。它依次把转换说明符与字段相匹配,并跳过它们之间的空格。要在每个输入项目之间至少键入一个换行符、空格或者制表符。惟一的例外就是%c说明,即使下一个字符是空白字符,也会读取那个字符,所以使用%c时要格外小心,我曾经犯过这样的错,调试了好久也没弄明白错在哪里。
scanf()函数所用的转换说明字符与printf()所用的几乎完全相同。主要的区别在于printf()把%f、%e、%E、%g和%0同时用于float类型和double类型,而scanf()只把它们用于float类型,而用于double类型时要求使用l修饰符。
二、机理
我们更仔细地研究 scanf()怎样读取输入。
假定使用了一个%d说明符来读取一个整数,scanf()函数开始每次读取一个输入字符,它跳过空白字符(空格、制表符和换行符)直到遇到一个非空白字符。因为它试图读取一个整数,所以scanf()期望发现一个数字字符或者一个符号(+或者-)。如果它发现了一个数字或一个符号,那么它就保存之并读取下一个字符;如果接下来的字符是一个数字,它保存这个数字,并读取下一个字符。就这样,scanf()持续读取和保存字符直到它遇到一个非数字的字符。如果遇到了一个非数字的字符,它就得出结论:己读到了整数的尾部。scanf()把这个非数字字符放回输入。这就意味着当程序下一次开始读取输入时,它将从前面被放弃的那个非数字字符开始。最后, scanf()计算它读取到的数字的相应数值,并将该值放到指定的变量中。
如果您使用了字段宽度,那么scanf()在字段结尾或者在第一个空白字符处(二者中最先到达的一个)终止。
如果第一个非空白字符不是数字,将会发生什么呢?比如说,是A而非一个数字?这时 scanf()会停在那里,并把A(或者不管是什么)放回输入。没把任何值赋给指定的变量,程序下一次读取输入时,它就在A处重新开始。如果程序中只有%d说明符 ,scanf()永远也不会越过那个 A (去读下一个)。而且,如果使用带有多个说明符的scanf()语旬. ANSIC 要求函数在第一个出错的地方停止读取输入 。
使用其他数字说明符读取输入与使用%d的情况相同。主要的区别在于scanf()也许会把更多的字符看作数字的一部分。例如,%x说明符要求scanf()识别十六进制数字a到f和A到F。浮点说明符要求scanf()识别小数点、指数记数法 ( e-notation )、新的p记数法( p-notation)。
如果使用%s说明符,那么空白字符以外的所有字符都是可接受的,所以scanf()跳过空白字符直到遇到第一个非空白字符,然后保存再次遇到空白字符之前的所有非空白字符。这就意味着使scanf()读取一个单词,也就是说,一个不包含空白字符的字符串。如果使用字段宽度, scanf()在字段的结尾或者第一个空白字符处停止。不能通过字段宽度使得scanf()用一个%s说明符读取多于一个字的输入。最后一点: 当scanf()把字符串放在一个指定的数组中时,它添加终止的’\0’使得数组内容成为一个C字符串。
如果使用 %c说明符,那么所有的输入字符都是平等的。如果下一个输入字符是一个空格或者换行符,将会把这个空格或换行符赋给指定的变量:不会跳过空白字符。
三、格式字符串中的常规字符
scanf()函数允许您把普通字符放在格式字符串中。除了空格字符之外的普通字符一定要与输入字符串准确匹配。
- 例如,如果无意间把逗号放在两个说明符之间:
scanf(“%d,%d”, &m,%n),
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()会跳到第一个非空白字符处。也就是说,命令scanf(“%c”, &ch)读取在输入中遇到的第一个字符,而scanf(” %c”,&ch)则读取遇到的第一个非空白字符。
四、scanf()函数的返回值
scanf()函数返回成功读入的项目的个数。如果它没有读取任何项目(当它期望一个数字而您却键入一个非数字字符串就会发生这种情况),scanf()会返回值0。当它检测到”文件结尾”时,返问EOF(EOF是在文件stdio.h定义的特殊值。一般#define指令把EOF的值定义为-1)。