34

“Thinking in Java, 2nd Edition”的第 4 章第 231 页中的“数组初始化”部分有这样的说法:

在 C 中初始化数组容易出错且乏味。C++ 使用聚合初始化使其更安全。Java 没有像 C++ 那样的“聚合”,因为 Java 中的一切都是对象。它确实有数组,并且数组初始化支持这些数组。

为什么在 C 语言中容易出错且乏味?聚合初始化是什么意思,为什么它更安全?我在 Bruce Eckel 的“Thinking in C++” (第 2 版)中看到了“聚合初始化”一章,但这并没有让我信服。

4

2 回答 2

30

首先,回答主要问题,聚合初始化意味着使用大括号括起来的初始化列表来初始化聚合的所有成员(即数组或结构[在 C++ 中,只有某些类型的结构算作聚合])。

明显地,

int ar[] = { 1 , 2 };

比安全

int ar[2];
ar[0] = 1;
ar[1] = 2;

因为后者为初始化单个元素的索引中的拼写错误和其他错误提供了充足的机会。

看看今天的 C 和 C++,我不清楚作者为什么要区分 C 和 C++。两种语言都支持数组的聚合初始化。

一种可能性是作者引用了 C 标准的旧版本。值得注意的是,在 ANSI C (C89) 中,对聚合初始化的使用有一个重要限制:所有初始化器都必须是常量表达式:

/* This is possible in C89: */
f(int i)
{ int ar[] = { 1 , 2 }; }

/* But this is not
   (because i is not a constant expression):
*/
f(int i)
{ int ar[] = { i , i+1 }; }

这是由于 C89 中的 3.5.7(引用我在这里找到的草稿):

具有静态存储持续时间的对象的初始化程序或具有聚合或联合类型的对象的初始化程序列表中的所有表达式都应为常量表达式。

这显然限制了聚合初始化的有用性(即使在 1989 年,我相信许多编译器也实现了扩展以启用非常量表达式的聚合初始化)。

后来的 C 标准版本没有这个限制,我相信 C++ 的标准化版本(从 C++98 开始)从来没有任何这样的限制。

我只能推测,但也许这就是作者的想法?

于 2013-07-18T01:44:47.987 回答
1

我假设作者警告您关于 C 和 C++ 中缺乏强制大小约束。在 C 和 C++ 中,数组衰减为指向其第一个元素的指针。然后它使用指针算术来查找您通过索引引用的元素。由于数组不是对象并且编译器不努力存储它们的大小,因此没有长度检查。在 Java 中,数组是对象,因此它们的大小是已知的。可以检查这个大小,这可以保护开发人员在超出数组边界时访问不属于他/她的内存。

我觉得奇怪的是,在这种情况下甚至使用了“C++ 使用聚合初始化使其更安全”的语句。

大多数现代语言通用的聚合初始化如下

int intArray[3] = {1,2,3};
int int2DArray[2][2] = {{1,2}, {3,4}};

这种类型的初始化假设您事先知道数组的大小及其内容。这种类型的初始化可以防止越界,并提供使用设定值初始化数组。也许在这种情况下,作者想到了一个开发人员,他声明了一个大小为 5 的静态 C 数组。然后这个开发人员创建了一个循环来初始化它的内容,但是超出了数组的边界一个,写入到不是他/他的内存中。她的。

于 2013-07-18T01:23:11.903 回答