【发布时间】:2010-11-27 16:55:04
【问题描述】:
当像这样在 C 中声明一个数组时:
int array[10];
整数的初始值是多少?我使用不同的编译器得到不同的结果,我想知道它是否与编译器或操作系统有关。
【问题讨论】:
标签: c arrays compiler-construction
当像这样在 C 中声明一个数组时:
int array[10];
整数的初始值是多少?我使用不同的编译器得到不同的结果,我想知道它是否与编译器或操作系统有关。
【问题讨论】:
标签: c arrays compiler-construction
如果数组在函数中声明,则值未定义。函数中的int x[10]; 表示:在不进行任何初始化的情况下获得10-int-size 内存区域的所有权。如果数组被声明为全局数组或函数中的static,则如果所有元素尚未初始化,则将其初始化为零。
【讨论】:
int array[10] = {0};。让编译器自动执行它只是意味着您正在编写仅在调试模式下工作的代码,并且在您发布它时会中断,或者其他人使用不同的选项编译它。
static 函数内定义的变量也将被初始化为零可能也是值得的。
按照标准的规定,所有全局和函数静态变量都会自动初始化为 0。自动变量不会被初始化。
int a[10]; // global - all elements are initialised to 0
void foo(void) {
int b[10]; // automatic storage - contain junk
static int c[10]; // static - initialised to 0
}
但是,无论其存储类如何,始终手动初始化函数变量是一个好习惯。要将所有数组元素设置为 0,您只需将第一个数组项分配为 0 - 省略的元素将自动设置为 0:
int b[10] = {0};
【讨论】:
auto 存储类)没有初始化而其他一切都初始化了?C 接近硬件;这是它最大的力量,也是它最大的危险。 auto 存储类对象具有随机初始值的原因是因为它们是在堆栈上分配的,并且设计决定不自动清除这些(部分是因为它们需要在每次函数调用时清除)。
另一方面,非auto 对象只需清除一次。另外,出于安全原因,操作系统必须清除分配的页面。所以这里的设计决定是指定零初始化。为什么堆栈的安全性也不是问题?实际上,一开始它是清除的。您看到的垃圾来自您自己的程序调用帧的早期实例以及它们调用的库代码。
最终结果是快速、节省内存的代码。组装的所有优点,没有任何痛苦。在 dmr 发明 C 之前,像 Basic 和整个 OS 内核这样的“HLL”实际上是作为巨大的汇编程序实现的。 (在像 IBM 这样的地方有一些例外。)
【讨论】:
根据 C 标准,6.7.8(注 10):
如果一个对象具有自动 存储持续时间未初始化 明确地,它的值是 不确定。
所以这取决于编译器。使用 MSVC,调试版本将使用 0xcc 初始化自动变量,而非调试版本根本不会初始化这些变量。
【讨论】:
C 变量声明只是告诉编译器留出并为您命名一个内存区域。对于自动变量,也称为堆栈变量,该内存中的值与之前的值没有变化。程序启动时将全局变量和静态变量设置为零。
未优化调试模式下的某些编译器将自动变量设置为零。但是,在较新的编译器中,将值设置为已知的错误值已变得很常见,这样程序员就不会在不知不觉中编写依赖于设置零的代码。
为了让编译器为你设置一个数组为零,你可以这样写:
int array[10] = {0};
更好的是用它应该有的值来设置数组。这样效率更高,并且避免了两次写入数组。
【讨论】:
在大多数最新的编译器(例如 gcc/vc++)中,部分初始化的本地数组/结构成员默认初始化为零(int)、NULL(char/char string)、0.000000(float/double)。
除了上面的局部数组/结构数据外,静态(全局/局部)和全局空间成员也保持相同的属性。
int a[5] = {0,1,2};
printf("%d %d %d\n",*a, *(a+2), *(a+4));
struct s1
{
int i1;
int i2;
int i3;
char c;
char str[5];
};
struct s1 s11 = {1};
printf("%d %d %d %c %s\n",s11.i1,s11.i2, s11.i3, s11.c, s11.str);
if(!s11.c)
printf("s11.c is null\n");
if(!*(s11.str))
printf("s11.str is null\n");
在 gcc/vc++ 中,输出应该是:
0 2 0 1 0 0 0.000000 s11.c 为空 s11.str 为空
【讨论】:
来自http://www.cplusplus.com/doc/tutorial/arrays/的短信
总结:
初始化数组。当声明一个 本地范围的常规数组(在 函数,例如),如果我们不 否则,其元素将 不被初始化为任何值 默认,所以他们的内容将是 在我们存储一些值之前不确定 在他们之中。全局元素和 另一方面,静态数组是 用他们的自动初始化 默认值,这对于所有 基本类型,这意味着它们是 用零填充。
在本地和全局这两种情况下,当 我们声明一个数组,我们有 分配初始值的可能性 通过 将值括在大括号 {} 中。 例如:
int billy [5] = { 16, 2, 77, 40, 12071 };
【讨论】:
来自 C 标准的相关部分(重点是我的):
5.1.2 执行环境
所有具有静态存储持续时间的对象应在程序启动前初始化(设置为其初始值)。
6.2.4 对象的存储时长
使用外部或内部链接或存储类说明符 static 声明其标识符的对象具有静态存储持续时间。
6.2.5 类型
数组和结构类型统称为聚合类型。
6.7.8 初始化
如果具有自动存储持续时间的对象未显式初始化,则其值不确定。如果具有静态存储持续时间的对象未显式初始化,则:
- 如果有指针类型,则初始化为空指针;
- 如果是算术类型,则初始化为(正或无符号)零;
- 如果是聚合,则每个成员都根据这些规则进行初始化(递归);
- 如果是联合,则根据这些规则(递归)初始化第一个命名成员。
【讨论】:
这取决于您的阵列的位置。
如果它是全局/静态数组,它将成为bss 部分的一部分,这意味着它将在运行时由 C 复制例程初始化为零。
如果是函数内的局部数组,则位于stack内,初始值未知。
【讨论】:
如果数组是在函数内部声明的,那么它的值是未定义的,但是如果数组声明为全局数组或者它在函数内部是静态的,那么数组的默认值为 0。
【讨论】: