*
问:转换说明
%i
也可以用于读写整数。
%i
和
%d
之间有什么区别?(p.29)
答:在
printf
格式串中使用时,二者没有区别。但是,在
scanf
格式串中,
%d
只能与十进制(基数为10)形式的整数相匹配,而
%i
则可以匹配用八进制(基数为8)、十进制或十六进制(基数为16)表示的整数。如果输入的数有前缀
0
(如
056
),那么
%i
会把它作为八进制数(➤7.1节)来处理;如果输入的数有前缀
0x
或
0X
(如
0x56
),那么
%i
会把它作为十六进制数(➤7.1节)来处理。如果用户意外地将
0
放在数的开始处,那么用
%i
代替
%d
读取数可能有意想不到的结果。因为这是一个陷阱,所以建议坚持采用
%d
。
问:如果
printf
函数将
%
作为转换说明的开始,那么如何显示字符
%
呢?
答:如果
printf
函数在格式串中遇到两个连续的字符
%
,那么它将显示出一个字符
%
。例如,语句
printf("Net profit: %d%%\n", profit);
可以显示出
Net profit: 10%
问:转义序列
\t
会使
printf
函数跳到下一个水平制表符处。如何知道水平制表符到底跳多远呢?(p.31)
答:不可能知道。打印
\t
的效果不是由C语言定义的,而是依赖于所使用的操作系统。水平制表符之间的距离通常是8个字符宽度,但C语言本身无法保证这一点。
问:如果要求读入一个数,而用户录入了非数值的输入,那么
scanf
函数会如何处理?
答:请看下面的例子:
printf("Enter a number: ");
scanf("%d", &i);
假设用户录入了一个有效数,后边跟着一些非数值的字符:
Enter a number: 23foo
这种情况下,
scanf
函数读取
2
和
3
,并且将23存储在变量
i
中,而剩下的字符(
foo
)则留给下一次
scanf
函数调用(或者某些其他的输入函数)来读取。另外,假设输入从开始就是无效的:
Enter a number: foo
这种情况下,没有值会被存储到变量
i
中,字符
foo
会留给下一次
scanf
函数调用。
如何处理这种糟糕的情况呢?后面将看到检测
scanf
函数调用是否成功(➤22.3节)的方法。如果调用失败,可以终止或者尝试恢复程序,可能的方法是丢掉有问题的输入并要求用户重新输入。(在第22章结尾的“问与答”部分会讨论有关丢弃错误输入的方法。)
问:我不能理解
scanf
函数如何把字符“放回原处”并在以后再次读取。(p.33)
答:我们知道,用户从键盘输入时,程序并没有读取输入,而是把用户的输入放在一个隐藏的缓冲区中,由
scanf
函数来读取。
scanf
函数把字符放回到缓冲区中供后续读取是非常容易的。第22章会更详细地讨论输入缓冲。
问:如果用户在两个数之间加入了标点符号(如逗号),
scanf
函数将如何处理?
答:先来看一个简单的例子。假设我们想用
scanf
函数读取一对整数:
printf("Enter two numbers: ");
scanf("%d%d", &i, &j);
如果用户输入
4,28
scanf
函数将读取4并且把它存储在变量
i
中。在寻找第二个数的起始位置时,
scanf
函数遇到了逗号。因为数不能以逗号开头,所以
scanf
函数立刻返回,而把逗号和第二个数留给下一次
scanf
函数调用。
当然,如果能确定数与数之间 始终 用逗号来分隔,我们可以很容易地解决这个问题,只要在格式串中添加逗号即可:
printf("Enter two numbers, separated by a comma: ");
scanf("%d,%d", &i, &j);