为什么数组需要在定义时设置维度?

时间:2014-03-26 09:22:11

标签: c# arrays

我只是想知道,为什么我们不能只定义这样的东西:

int[] arr = new int[];
arr[0] = 1;

像列表一样,自动调整大小。 我想知道的是为什么这是不可能的,我们需要每次按以下方式设置大小:

int[] arr = new int[1];
arr[0] = 1;

5 个答案:

答案 0 :(得分:12)

List<T>调整大小是基于在需要时在幕后创建新数组。

想想这里的底层实现是什么样的。分配数组时,它会保留一块内存,并且引用有效地直接指向该内存。如果您需要存储的值多于您保留的值,则需要在其他位置分配更多内存...但您无法更改引用以引用该新内存,因为这些引用都是全部在这个地方。 (数组不知道引用它的是什么。)

显而易见的方法是拥有一个间接级别 - 以便初始引用是一个跟踪真实数据存储位置的对象,因此它可以在需要时重新分配至。这正是List<T>所做的......但它确实意味着有额外的间接水平。这会带来效率上的成本,部分原因在于您可能会在List对象本身的内存中获得很长的实际数据,这对缓存来说并不好...... 简单地通过一个额外的间接层本身就有成本。

基本上,如果您想要动态大小的集合,请使用List<T> - 这就是它的用途。如果您从一开始就知道最终尺寸,并希望从更接近金属的位置获益,那么#34;数组的方面,改为使用它们。

数组是一个相对较低级别的概念 - 如果你想要一个高级抽象,请使用一个......

答案 1 :(得分:7)

因为数组在内存中是连续的,所以在创建内容时必须为其内容分配足够的内存。

假设您有一个包含100个项目的数组。现在你再添加1个,你必须在第100个项目后面声明内存地址。如果该地址已被使用该怎么办?

这就是你无法动态调整数组大小的原因。

答案 2 :(得分:2)

我的猜测是&#39;因为它以这种方式指定&#39; - 这种情况给出了阵列特定的性能特征和优化能力,这是非常需要的。虽然这些优点已经被设计者注意到,并且存在于也使用类似结构(C,C ++,Java - 脚注1)的影响语言中,但他们真的可以将其定义为任何

例如,

List<T>必须调整内部数组的大小,通常分配比必要更多的内存(除非你碰巧使用的内容与分配的内容一样多)以及创建垃圾。

1.8 of the C# language specification has the following

  

数组是一个包含许多变量的数据结构   通过计算索引访问。包含的变量   数组,也称为数组的元素,都是一样的   type,此类型称为数组的元素类型。

     

数组类型是引用类型,以及数组变量的声明   只需留出空间来引用数组实例。实际   使用new在运行时动态创建数组实例   运营商。 新操作指定新数组的长度   实例,然后在实例的生命周期内修复。   数组元素的索引范围从0到Length - 1   new运算符自动初始化数组的元素   它们的默认值,例如,对于所有数字类型,它都为零   并且对所有引用类型都为null。

此外,任何人都没有提到 - 其他数组边界检查被认为是一个软件工程原理&#39; - 正如在the ECMA 334 Spec中描述他们的设计目标所述:

  

语言及其实现应该提供支持   软件工程原理,如强类型检查,数组   边界检查,检测使用未初始化变量的尝试,   和自动垃圾收集。软件稳健性,耐用性和   程序员的工作效率很重要。

Footnote 1 - Introduction of C# language spec

  

C#(发音为“See Sharp”)是一个简单,现代,面向对象的,而且   类型安全的编程语言。 C#源于C家族   语言和 将立即为C,C ++和Java所熟悉   程序员。

答案 3 :(得分:1)

这是因为数组分配内存,框架需要知道多少。

如果您想要动态调整大小&#39;,请使用List

列表实际上包装了一个数组。在当前数组中添加更多项目时,会创建一个新数组(通常为double size),旧项目将移动到新数组。相反,删除也是如此。

答案 4 :(得分:1)

因为数组的大小是定义的静态而不是动态的。

如果你想要一个动态大小的集合,还有其他的,比如你提到的列表,可用。

你可以做的是延迟声明数组的大小:

int[] numbers;
numbers = new int[10];  
numbers = new int[20];