输入下面的程序,你就会明白为什么了:
#include <stdio.h>
int main (void) {
int val = 4096;
printf ("Enter your character: ");
scanf ("%c",&val);
printf ("integer val = %d, character val = %c\n", val, val);
return 0;
}
用gcc -Wall(所有警告)编译它,给出:
qq.c: In function 'main':
qq.c:6: warning: format '%c' expects type 'char *',
but argument 2 has type 'int *'
(确保您在编译时启用所有警告的充分理由)并运行它会得到与您发现的相同的结果:
Enter your character: f
integer val = 4198, character val = f
原因是scanf 的工作方式与变量在内存中的布局方式相结合。
scanf 将简单地获取一个字符并将其放入内存中。因为你给了它一个整数的地址,而且这个整数是小端的,它只会覆盖那个整数的最低有效字节(LSB)。把那段记忆看作一个重叠的区域,你就会明白为什么:
+--- The address passed to scanf.
|
V
+------+
| char | <-- Treated as char.
+------+------+------+------+
| lsb | | | msb | <-- Treated as integer (assumes 32-bit).
+------+------+------+------+
因为scanf 没有触及整数的最右边的字节,所以它们在调用之前保留了它们所持有的任何内容。在我的代码中,我明确地将其强制为4096,但是,如果您的声明是未初始化的int val;,则内容将是不确定的。事实上,当我删除初始化时,我得到了1629542246(0x6120D766,你仍然可以看到 LSB 设置为0x66 或f)。
这只是意味着我的整数在scanf 调用之前看起来像这样:
+------+
| ?? |
+------+------+------+------+
| ?? | d7 | 20 | 61 |
+------+------+------+------+
而scanf 调用仅更改了?? 位。