10 使用数组

1.声明和创建数组

数组:无序的元素序列。数组中的所有元素都具有相同类型。数组中的元素存储在一个连续性的内存块中,并通过索引来访问。

 

1.1声明数组变量

语法:先写它的元素类型名称,后跟一对方括号([ ]),最后写变量名。

例如:

int[] array;

数组元素并非只能是基本数据类型。还可以是结构、枚举或类。

例如:为了创建由Date结构构成的数组,可以像下面这样写:

Date [] date;

1.2创建数组实例

无论元素是什么类型,数组始终都是引用类型。

为了创建数组实例,要先写new关键字,后跟元素的类型名称,然后在一对方括号中指定要创建的数组的大小。创建数组实例时,会使用默认值(0,null 或者false,分别取决于是数值类型,是引用类型,还是Boolean类型)对其元素进行初始化。例如,针对早先声明的pins数组变量,以下语句创建并初始化由4个整数构成的新数组:

int [] pins;

pins = new int[4];

内存图:

动态分配数组大小:

int size = int.Parse(Console.ReadLine());

int [] pins = new int[size];

1.3填充和使用数组

大括号中的值的数量必须和要创建的数组实例的大小完全匹配:

int[] pins = new int[3]{ 9, 3, 7, 2 }; //编译时错误

int[] pins = new int[4]{ 9, 3, 7);//编译时错误

int[] pins = new int[4]{ 9, 3, 7, 2 }; // 正确

初始化数组变量时可以省略new表达式和数组大小。编译器根据初始值的数量来计算

大小,并生成代码来创建数组。例如:

int [] pins = {9,3,7,2};

创建由结构或对象构成的数组时,可以调用构造器来初始化数组中的每个元素,例如:

Time [] schedule = { new Time(12,30),new Time(5,30)};

1.4创建隐式类型的数组

声明数组时,元素类型必须与准备存储的元素类型匹配。例如,将pins 声明为int类型的数组(就像前面的例子那样),就不能把double, struct, string 或其他非int类型的值保存到其中。如果在声明数组时指定了初始值列表,就可以让C#编译器自已推断数组元素的类型,如下所示:

var names = new[]{"John","Diana","James"};

在这个例子中,C#编译器推断names是string类型的数组变量。注意语法有两个特别之处。首先,类型后的方括号没了,本例中的names变量被直接声明为var,而不是var[]。其次,必须在初始值列表之前添加new[]。

使用这个语法,必须保证所有初始值都有相同类型。下例将导致编译器报错:“找不到隐式类型数组的最佳类型。"

var bad = new[]{ "John","Diana",23,54};

但有时编译器会把元素转换为不同的类型一前 提是结果有意义。下例的numbers会被推断成double数组,因为常量3.5和99.999都是double值,而C#编译器能将整数值1和2转换成double:

var numbers = new[]{1,2,3.5,99.999};

一般最好避免混合使用多种类型,不要单纯寄希望于编译器帮自己转换。

 

隐式类型的数组尤其适合第7章描述的匿名类型。以下代码创建由匿名对象构成的数

组,其中每个对象都包含两个字段,分别指定了我的家庭成员的姓名和年龄:

var name = new[] { new {Name = "John", Age = 50 ],

  new (Name = "Diana", Age= 50 }

  new {Name = "James", Age = 23 },

  new {Name = "Francesca", Age = 21 } };

匿名类型中的字段对于每个数组元素都必须相同。

 

1.5访问单独的数组元素

必须通过索引来访问单独的数组元素。数组索引基于零,第一个元素的索引是0而不

是1。索引1访问的是第二个元素。例如,以下代码将pins数组的索引为2的元素(第三

个元素)的内容读入-一个int变量:

int myPin;

myPin = pins[2];

类似地,可通过索引向元素赋值来更改数组内容:

myPin = 1645;

pins[2] = myPin;

所有数组元素访问都要进行边界(上下限)检查。使用小于日或大于等于数组长度的整

数索引,编译器会抛出IndexoutofRangeException异常,如下例所示:

try

{

    int[] pins = {9,3,7,2};

    Console.WriteLine(pins[4]);  //错误,第4个也是最后一个元素的索引是3

}

catch(IndexOutOfRangeException ex)

{

    …

}

 

1.6遍历数组

所有数组都是Microsoft .NET Framework的System .Array类的实例,该类定义了许多有用的属性和方法。例如,可以查询Length 属性来了解数组中包含多少个元素,并借助for语句来遍历所有元素。下例将pins数组的各个元素的值输出到控制台:

int[] pins = {9,3,7,2};

for(int index = 0;index <pins.Length;index++)

{

    int pin = pins[index];

    Console.WriteLine(pin);

}

再介绍一个foreach语句来遍历数组:

int[] pins = {9,3,7,2};

foreach (int pin in pins)

{

    Console.WriteLine(pin);

}

foreach语句是遍历数组的首选方式,它更明确地表达了代码地目的,而且避免了使用for循环地麻烦。但少数情况下for语句更佳,如下所示:

(1)foreach语句总是遍历整个数组。如果只想遍历数组的一部分(例如前 半部分),或者希望中途跳过特定元素(例如每隔两个元素就跳过一个), 那么使用for语句将更容易。

(2)foreach 语句总是从索引0遍历到索引Length-1。要反向或者以其他顺序遍历,更简单的做法是使用for语句。

(3)如果循环主体需要 知道元素的索引,而非只是元素的值,就必须使用for语句。

(4)修改数组元素必须使用 for语句。这是因为foreach语句的循环变量是数组的每个元素的只读拷贝。

 

1.7数组作为方法参数和返回值传递

方法可获取数组类型的参数,也可把它们作为返回值传递。

例如:数组作为参数

public void ProcessDate(int[] data)

{

    foreach(int i in data)

    {

    //…

    }

}

方法要返回一个数组,返回类型必须是数组类型。方法内部要创建并填充数组。下例提示用户输入数组大小,再输入每个元素的数据。最后,方法返回创建好的数组。

public int[] ReadData()
{
    Console .WriteLine("How many elements?");
    string reply = Console. ReadLine();
    int numElements = int. Parse(reply);
    int[] data = new intfnumElements];
    for (int i = 0; i < numElements; i++)
    {
        Console.WriteLine($"Enter data for element ({1});
        reply = Console.ReadLine();
        int elementData = int.Parse(reply);    
        data[i] = elementData;
    }
    return data;
}

可像下面这样调用ReadData:

int[] data = ReadData();

 

补充:

Main方法的数组参数

你可能早已注意到应用程序的Main方法获取- 个字符串數组作为参数:

static void Main()
{

    //…

}

Main方法是程序运行时的入口方法。从命令行启动程序时,可以指定附加的命令行参数。Microsof Windows操作系统将这些参数传给CLR,后者将它们作为实参传給Main方法。这个机制允许在程序开始运行时直接提供信息,而不必交互式地提示输入信息。编写能通过自动脚本运行的实用程序时,这个机制相当有用。下例来自一个用于文件处理的MyFileUtil实用程序。它允许在命令行输入一一组文件名,然后调用ProcessFile方法(这里

没有显示)处理每个文件:

static vold Main(string[] args)
{

    foreach (string fllename in args)
    {
        Procesflle(filename);
    }

}

可以在命令行上像下面这样运行MyFileUil程序:

MyFlleUtil C:\Temp\TestDatadat C: \Users\John\Documents\MyDoc .txt

每个命令参数都以空格分隔。由MyFileUil程序负责验证实参的有效性。

 

1.8复制数组

数组是引用类 型(记住,数组是System.Array类的实例)。数组变量包含对数组实例的引用。这意味着在复制了数组变量之后,将获得对同一个数组实例的两个引用。例如:

int[] pins = {9,3,7,2};

int[] alias = pins;//alias和pins现在引用同一个数组实例

在这个例子中,修改pins[1]的值,读取alias[1]时也会看到改动。要完全复制数组实例,获得堆上实际数据的拷贝,必须做两件事情。首先,必须创建类型和大小与原始数组一样的新数组实例,然后将数据元素从原始数组逐个复制到新数组,如下例所示:

int[] pins={9,3, 7,2 };

int[] copy =new int[pins .Length];

for (int 1=0;1 < copy.Length; 1++)

{

    copy[i] = pins[i];

}

注意,上例使用原始数组的Length属性指定新数组大小。

使用System. Array类提供了一些方法来复制数组:

(1)CopyTo()

下例从索引0开始将pins数组的所有元素复制到copy数组:

int[] pins - {9,3,7, 2};

int[] copy = new int[pins.Length];

pins.CopyTo(copy, 0);

(2)Copy()

复制值的另一个办法是使用System.Array的静态方法Copy。和CopyTo一样, 目标数组必须在调用Copy之前初始化:

int[] pins={9,3,7, 2};

int[] copy = new int[pins ,Length];

Array,Copy(pins, copy, copy. Length);

注意:Array.Copy方法的长度参数必须是一个有效的值。提供负值会抛出ArgumentoutOfRangeException异常。提供比元素数量大的值,会抛出ArgumentException异常。

 

(3)Clone()

使用System. Array的实例方法Clone。它允许在一次调 用中创建数组并完成复制。

int[] pins={9, 3,7,2};

int[] copy = (int[])pins.Clone();

1.9使用多维数组

下列代码创建包含24个整数的二维数组items,可将二维数组想象成表格,第一维是表行,第二维是表列。

int[ ; ] items =new int[4, 6];

 

访问二维数组元素:

items[2, 3]=99;//将单元格(2, 3)的元素设为99

items[2, 4] = items [2,3]; /将单元格(2, 3)的元素复制到单元格(2, 4)

items[2, 4]++;//递增单元格(2, 4)的整数值

数组维数没有限制。以下代码创建并使用名为cube的三维数组。访问三维数组的元素必须指定3个索引。

int[, ] cube . new int[5, 5, 5];

cube[1, 2, 1] .101;

cube[1, 2, 2]=cube[1, 2, 1]*3;

使用超过三维的数组时要小心,数组可能耗用大量内存。上例的cube 数组包含125个元素(5*5*5)。而对于每一维大小都是5的四维数组,则总共包含625个元素。使用多维数组时,一般都要准备好捕捉并处理OutOfMemoryException异常。

 

1.10创建交错数组

因为多维数组可能消耗大量内存。如果应用程序只使用每一列的部分数据,为未使用的元素分配内存就是巨大的浪费。这时可以考虑使用交错数组(或称为不规则数组),其每一列的长度都可以不同,如下所示:

int[][] items=new int[4][];

int[] columnForRow0 =new int[3];

int[] columnForRow1 =new int[10];

int[] columnForRow2 =new int[40];

int[] columnForRow3 =new int[25];

items[0]=columnForRov0;

items[1]=colunnForRow1;

items[2]=columnForRow2;

items[3]=columnForRow3;

本例第一列3个元素,第二列10个元素,第三列40个元素,最后一列25个元素。交错数组其实就是由数组构成的数组。和二维数组不同,交错数组只有一维,但那一-维中的元素本身就是数组。除此之外,items 数组的总大小是78个元素而不是160个:不用的元素不分配空间。

参考书籍:《Visual C#从入门到精通》

发布了46 篇原创文章 · 获赞 53 · 访问量 3712

猜你喜欢

转载自blog.csdn.net/qq_38992372/article/details/104992503
今日推荐