《Visual C# 最佳实践》第三章 数组结构 (一):数组
时间:2010-10-17 来源:邹俊才
本章的学习重点:
◆ 数组概念
◆ 二维数组
◆ 数组初始化
◆ 注意事项
3.1数组
首先,将介绍几个概念来帮助我们理解数组的概念。数组是一种具有相同类型的变量的集合,例如一组整数、一组字符等。组成数组的这些变量被称为数组的元素,元素的个数也称为数组的长度、数组的容量,容量一旦创建了,便固定了,这时,数组的元素个数也就不能增加或减少了。
每个数组元素都有一个编号,这个编号叫做下标,这个下标也称为索引,一个有n个元素的数组,其索引是从0~n-1为止。索引以及容量是数组的特性,在数组创建的时候便固定了,当利用索引操作时,不可以超出定义的容量,以免发生数组索引超出界限的错误。
3.1.1数组概念
数组是相同类型的对象的集合。由于数组几乎可以为任意长度,因此可以使用数组存储数千乃至数百万个对象,但必须在创建数组时就确定其大小。数组中的每项都按索引进行访问,索引是一个数字,指示对象在数组中的存储位置或槽。数组既可用于存储引用类型,也可用于存储值类型。下面向大家介绍各种常用数组。
数组是一个经过索引的对象集合,一维数组以线性方式存储固定数目的项。声明如下:
type[] arrayName;
一般会同时初始化数组中的元素,如下所示:
int[] array = new int[5];
定义数组的时候,可以预先指定数组元素的个数,在“[]”中定义数组的元素个数,这里我们把元素个数定义为5。元素个数可以通过数组名的“Length”属性获得。而在使用数组的时候,可以在“[]”中加入下标来取得对应的数组元素。数值数组元素的默认值为零,引用元素的默认值为 null,但我们可以在创建数组的过程中初始化值,如下所示:
int[] array1 = new int[] { 1, 3, 5, 7, 9 };
或者甚至这样来初始化:
int[] array2 = {1, 3, 5, 7, 9};
数组的索引从零开始,因此数组中的第一个元素的索引为0,下面我们来看一个范例:
1 using System;
2 namespace Microsoft.Example
3 {
4 class TestArray
5 {
6 static void Main(string[] args)
7 {
8 string[] days = { "Sun", "Mon", "Tue", "Wed", "Thr", "Fri", "Sat" }; //定义一个数组
9 System.Console.WriteLine(days[0]); //输出索引为0的值
10 }
11 }
12 }
上述代码中,第8行定义了一个数组,同时还使用数据初始化了这个数组。我们前面说过,数组初始化的时候,它的索引是从零开始的,所有,要想读取索引为零的数据,就得使用第9行的代码,使用[0]来定位数据的位置。
输出结果:Sun
另一细节是,foreach 语句通常用来访问数组中存储的每个元素,如下所示:
int[] numbers = { 4, 5, 6, 1, 2, 3, -2, -1, 0 };
foreach (int i in numbers)
{
System.Console.Write("{0} ", i);
}
输出结果:4 5 6 1 2 3 -2 -1 0
注意,数组的大小不是其类型的一部分,而在 C 语言中它却是数组类型的一部分。这使我们可以声明一个数组并向它分配任意数组,而不管数组长度如何,如下所示:
int[] numbers; //定义一个可以任意大小的int数组
numbers = new int[10]; //numbers是一个有10个元素的数组
numbers = new int[20]; //现在,number是一个有20个元素的数组
3.1.2二维数组
生活中,很多事情没有办法使用一维数组来实现。比如一个方队的队伍,包含有很多排,每一排又有很多人。一维数组只能表示一个纵队,无法容纳我们一个方队的队伍。为了解决这个问题,我们可以使用C#言语中的多维数组。多维数组的一种变体是交错数组,即由数组组成的数组。从概念上来说,两维数组类似于网格,三维数组则类似于立方体。本文我们重点向大家介绍二维数组:
我们可以这样来定义一个二维数组,如下所示:
int[,] array2D = new int[2,3];
上述定义中,我们声明了一个变量名为array2D的二维数组,同时还声明了它的容量,可以容纳2行的队伍,每行队伍可以站3个人。
我们也可以在创建数组的过程中初始化值,如下所示:
int[,] array2D2 = { {1, 2, 3}, {4, 5, 6} };
在开发过程中,我们经常需要读取数组中的值,下面我们来看一个范例:
01 using System;
02 namespace Microsoft.Example
03 {
04 class TestReadArray
05 {
06 static void Main(string[] args)
07 {
08 int[,] array2D = { { 1, 2, 3 }, { 4, 5, 6 } }; //定义一个二维数组
09 for (int i = 0; i < 2; i++) //遍历每一行
10 {
11 for (int j = 0; j < 3; j++) //遍历每一列
12 {
13 System.Console.Write(array2D[i, j]); //读取二维数组中的元素
14 }
15 System.Console.WriteLine();
16 }
17 }
18 }
19 }
上述代码中,第8行定义了一个二维数组array2D,并进行了初始化。然后,我们使用for循环来遍历数组里面的元素。这里我们需要使用两个循环,第一个循环用来遍历行数,第二个循环用来遍历一行中的列数。最后根据索引输出数组元素的值。
最后的结果是:
123
456
同样,修改数组一样方便,如下所示:
for (int i=0; i<2; i++)
{
for (int j=0; j<3; j++)
{
array2D[i,j] = (i + 1) * (j + 1); //修改二维数组中的元素
}
}
3.1.3数组初始化
使用C# 数组时,大家经常会遇到C# 数组初始化问题,搞不清楚各种初始化操作,这里将介绍C#数组初始化问题的解决方法。
1、int[] intArray = new int[3]{2, 3, 4} 的花括号被称为数组初始化器,数组初始化器只能在声明数组变量时使用,不能在声明数组之后使用C# 数组初始化,还可以不指定数组的大小 int[] intArray = new int[]{2, 3, 4} 编译器会自动计算,使用C#编译器还有一种更简化的形式 int[] intArray = {2, 3, 4};
2、用括号声明的数组,其实在后台使用C# 语法,创建一个派生于基础Array的新类。这样,就可以使用Array类为每个C# 数组定义的方法和属性。例如:Length属性,还可以使用foreach语句迭代数组,其实这是使用了Array类中的GetEnumerator()方法,或者说在Array类中实现了枚举器。
3、Array类是一个抽象类,不能使用构造函数来创建数组,除了可以使用C# 语法创建数组实例外,还可以使用它的CreateInstance()静态方法创建数组,如果事先不知道元素类型,或者想创建索引不基于0的数组,就可以使用静态方法。
4、数组是引用类型,所以将一个数组赋予另一个数组变量,就会得到两个指向同一个数组的变量。而复制数组实现ICloneable接口。这个接口定义的Clone()方法会创建一个数组的浅副本,也就是说,如果数组元素是值类型,就会复制所有的值,如果数组包含的是引用类型,则不复制元素本身,而只是复制引用。如果需要包含引用类型的数组的深副本,就必须迭代数组,创建新对象。
5、Array类实现了对数组中元素的冒泡排序。Sort()方法需要数组中的元素实现IComparable接口。简单类型,如String和Int32实现了IComparable接口(升序),调用语法为Array.Sort()。
3.1.4注意事项
C#数组的工作方式与大多数其他流行语言中的工作方式类似,但还有一些差异应引起注意。声明数组时,方括号 ([]) 必须跟在类型后面,而不是标识符后面。在 C# 中,将方括号放在标识符后是不合法的语法。
int[] table; //合法
int table[]; //不合法
数组上的操作一般有:
取值操作:给定一组下标,读其对应的数据元素;
赋值操作:给定一组下标,存储或修改与其对应的数据元素;
清空操作:将数组中的所有数据元素清除;
复制操作:将一个数组的数据元素赋给另外一个数组;
排序操作:对数组中的数据元素进行排序,这要求数组中的数据元素是可排序的;
反转操作:反转数组中数据元素的顺序。