假设代码的其余部分没有任何问题,声明变量的顺序应该没有任何区别。声明的顺序不需要与它们在内存中的布局方式有任何关系。即使确实如此,您也可以通过名称来引用变量;只要你的代码是正确的,引用i
是对i
,编译器将生成正确访问变量所需的任何代码。
现在如果你这样做:
int i;
scanf("%c", &i);
那么你做错了什么。scanf
with a "%i"
格式需要一个char*
论点,它指向char
将存储值的对象。你给它一个int*
而不是一个char*
。因此,你的程序的行为是未定义的;语言标准没有说明它的行为方式。
那么为什么它看起来工作正常呢?可能发生的情况是scanf
处理的地址int
object i
就好像它是一个指向char
。它可能会指向表示的第一个字节i
;例如,i
可能是 32 位,指针将指向这些位的前 8 位。 (它们可能是高位或低位,具体取决于系统。)
现在当你打印的值i
:
printf("%d\n", i);
的内容i
例如,1 个字节由您刚刚读入的任何字符组成,3 个字节是垃圾。这 3 个垃圾字节很可能全部为零,但它们可以是任何东西。如果垃圾字节恰好为 0,并且第一个字节恰好是高位字节(即,您位于大尾数法 http://en.wikipedia.org/wiki/Big_endian机),那么您很可能会得到“正确”的输出。
但不要这样做。由于行为是未定义的,它可以“正确”工作多年,然后在最糟糕的时刻彻底失败。
这里的教训是,C 倾向于假设你知道自己在做什么。有一个lot具有未定义行为的构造,这意味着它们无效,但编译器和运行时系统都不需要告诉您存在问题。与大多数其他语言相比,C 语言更需要程序员将事情做好。编译器(和其他工具)会告诉你some错误,但不是全部。
在存在未定义行为的情况下,声明变量的顺序can做出改变。例如,如果您编写的代码读取或写入超过变量的末尾,那么那里存储的内容可能很重要。但是,在程序运行之前,不要试图随意更改声明。摆脱未定义的行为,以便顺序doesn't matter.
解决方案:首先不要犯错误。 (当然,说起来容易做起来难。)
命名约定会很有帮助。如果你打电话给你的char
多变的c
, 和你的int
多变的i
,而不是反之亦然,这样可以更容易地跟踪哪个是哪个。
But c
是一个合理的名称int
用于保存输入字符值的变量——不适用于scanf
, 但对于getchar()
, as in:
int c;
while ((c = getchar()) != EOF) {
/* ... */
}