3.8 在程序运行时提供数据
如果需要在程序运行期间由程序的使用者给变量输入一个值,可以调用库函数scanf()。和调用printf()一样,使用scanf()也需要在调用前加上预处理命令#include<stdio.h>,如果这条命令已经写了,就不必再写了。
scanf()函数的调用格式和printf()很类似,()内一般至少要写一个字符串文字量。举个最简单的例子:
字符串中的内容是要求你在键盘上键入哪些字符,这个字符串通常叫格式字符串(Format String)。在这个例子中要求你依次键入a、b、c 3个字符,然后回车就可以了。
但是这样的输入毫无意义,因为没有给程序提供任何有用的信息。所以scanf("abc");这样的使用方法是极其罕见的。多数情况下scanf()用于使程序获得一个值并把这个值存储在内存中适当的位置(最简单的情况就是存放在某个变量内存中)。下面再来看一个例子:
在这个例子中,字符串中的内容依然是要求你在键盘上键入哪些字符,输入的字符序列被称为输入流(Input Stream)。但是要注意的是字符串中的%d不是要求你键入%和d。在调用printf()函数时,“(”后面第一个字符串中的%通常是一个标志,它和其后面一个或多个字符构成一个整体。scanf("abc%d",&i);中的%d的含义是你在键盘上键入的字符序列将被scanf()函数解释为一个十进制数,然后把你键入的内容转变成内存中的二进制形式,&i表示把这个转变后的二进制数复制到i所占据的那块内存中去。“%d”这种东西叫做转换说明(Conversion Specification)
这样,如果你在键盘上键入a、b、c、1、2、3,那么scanf()在读取a、b、c之后将把你键入的1、2、3理解为十进制格式的123,然后转化成二进制形式:
再复制到i所代表的那块连续的32bits内存的中去。这样i的值就成了123(用十进制来说)。
现在你可能会发觉,你输入的a、b、c实际上毫无意义。是的,如果你意识到了这点,你就会知道下面的写法是多么的似是而非且画蛇添足:
这相当于要求运行程序的人(也可能就是你自己)平白无故地多输入了8个毫无意义的字符:“a”、“=”、“,”、“b”、“=”、“,”、“c”、“=”。
好的写法大致是下面这个样子:
另外一个编程常见的恶习是把“scanf("%d",&i);”写成“scanf("%d\n",&i);”。其中的\n也可能被写成了空格或\t,这样你会发现“scanf("%d\n",&i);”这句在执行时,在你输入十进制字符串后无论回车多少次都不会结束。这是因为在scanf()函数格式字符串中的任何一个空格、\t或\n(统称空白符,对应的键盘上的键这里称为空白键)都相当于键盘上键入的无穷多个连续的[SP](空格)、[Tab](跳格)或[CR](回车换行)。
结论是:在调用printf()时,在格式字符串中添加空白符和非空白符通常是一种良好的编程习惯,因为可以使输出更加清晰;而在调用scanf()函数时,在格式字符串中添加空白符和非空白符通常是一种编程恶习。
从键盘输入多个变量的值时,可以参看下面的写法:
这时键盘上输入的两个十进制数的内容要用空白键(一个或多个)分隔开。比如:
此外特别要注意的是在变量名之前通常要写&这个符号,这一点特别容易被初学者忘记。因此需要切记!