知识点 02 · 格式化输入输出¶
本页最后更新于 ,内容可能过时
scanf/printf 的格式串必须与参数类型匹配,这是本课程年年考的点。
1 · double 配 %f:格式串类型不匹配¶
如下程序,scanf 输入:1<B>.234<CR>(其中 <B> 表示空格,<CR> 表示回车),输出( )。
- A. 1.234
- B. 1.23
- C. 1.00
- D. 以上答案均不是
答案
D
解析
陷阱在 %f。scanf 的 %f 要求的是 float*,而 &x 是 double*——两者类型不匹配。
scanf 会按 float(4 字节)去写这 8 字节的 double,读进来的数据是错的,所以输出既不是 1.23 也不是 1.234,只能是"以上答案均不是"。
正确写法是 scanf("%lf", &x)(printf 则 %f 与 %lf 都行,因为可变参数会做默认实参提升)。
scanf 里 double 必须写 %lf。
2 · 同一个陷阱换个数¶
有如下程序,scanf 输入:1234<B>.5678<CR> 后(其中 <B> 表示空格,<CR> 表示回车),printf 输出( )。
- A. 1234.5678
- B. 1234.56
- C. 1234.00
- D. 以上答案均不是
答案
D
解析
同一个陷阱、同一段程序,只是输入的数字换了——可见这个考点年年考。
scanf("%f", &x) 里的 %f 要 float*,&x 却是 double*,类型不匹配导致读入的数据本身就是错的,跟输入的是 1 .234 还是 1234 .5678 无关,四个具体数值选项(1234.5678 / 1234.56 / 1234.00)一个都不对。
改成 scanf("%lf", &x) 才会输出 1234.56。
3 · 四个输入输出语句谁不会出错¶
请指出以下能够正确运行的输入输出语句。
A)
B)
C)
D)
答案
C
解析
先把三个错项排掉——A:b 定义了但从未初始化,直接 scanf("%d", b) 就是往一个野指针写数据(*b 处应补 &a,正确写法是 scanf("%d", &a));
B:char d[2] 存不下 "abc" 那类字符串所需的结束符 '\0',%s 找不到终止符会一直往后续内存读下去(应补上 '\0');
D:scanf("%f", c) 漏了取地址符 &,c 是变量值不是指针,直接崩。
C 是唯一"不会立刻出错"的:&a 是 float*,%d 会把它当整数打印,即打印地址。
严格说
严格说,用 %d 去打印一个指针属于实现定义行为(64 位机器上 int 4 字节、指针 8 字节,理论上可能截断),所以 C 并不是"标准意义上完全正确"。
但本题问的是"能够正确运行",A/B/D 是当场崩溃或未定义行为,只有 C 能跑通——这是本题的命题取向,考试选 C 即可。
4 · 能正确输出内容的代码片段¶
下列代码片段可以正确输出内容的是?
- A.
printf("%d", 'A'-'a'); - B.
scanf("%d", NULL); - C.
char str[3]="abc"; printf("%s",str); - D.
printf("%f", "123.45");
答案
A
解析
A 正确:字符常量参与算术运算时按 int 用,'A'-'a' = 65 - 97 = -32,用 %d 输出完全合法。
B 把 NULL 当作 int* 传给 scanf,等于往地址 0 写数据,运行时崩溃。
C 是最经典的陷阱:char str[3] 只有 3 字节,装不下 "abc" 加结束符 '\0' 共 4 字节,字符串没有终止符,printf("%s") 会越界一直读到内存里的随机 \0 为止——能"编译过",但输出内容不可预期。
D 用 %f 去打一个 char*("123.45" 是字符串字面量的地址),格式与参数类型不匹配,属未定义行为。