第5章 数组与字符串 CHAPTER 5         本章要点: * 一维数组的介绍; * 二维数组的介绍; * 交错数组的使用; * Array类及其方法的应用; * 字符串及其应用; * StringBuilder类及其应用。 5.1 数组概述   前面已经学习了变量的使用,知道变量的作用是存储数据。现在的问题是,如果我们有多个相同类型的数据需要保存,那应该如何处理呢?难道需要使用多次变量定义?正确的答案是使用数组类型,这是C#提供的专门用于处理大量相同类型数据的简便方法。可以这样理解:定义普通变量是申请一块内存保存一个数据,而定义数组变量则是申请一段连续的内存保存多个数据。比如定义100个学生,就不需要再定义100次学生变量了。只需要将这100个学生看成一个整体,定义一个数组变量即可。但在内存中,这个数组变量则包含了100个学生变量所占的内存区域。   数组是具有相同数据类型的一组数据的集合,例如,球类的集合有足球、篮球、羽毛球等;电器集合有电视机、洗衣机、电风扇等。前面学过的变量用来保存单个数据,而数组则保存的是多个相同类型的数据。数组与单个变量的内存区域比较如图5.1所示。   数组是通过指定数组的元素类型、数组的秩(维数)和数组每个维度的上限和下限来定义的。因此一个数组的定义需要包含以下几个元素:元素类型、数组的维数、每个维度的上下限。   数组的定义语法如下: 数据类型??数组名 = new 数据类型[数组长度]   例如: int[] arr1 = new int[10]; //定义一个名为arr1的int型数组,其最多容纳10个元素。   对数组的定义的组成要素注解如图5.2所示。 图5.2 数组定义的组成要素   数组中的每一个变量称为数组的元素。数组能够容纳元素的数量称为数组的长度。数组中的每个元素都具有唯一的索引与其对应。数组的索引从零开始。在程序设计中引入数组,将若干个元素看作一个整体,可以更为有效地管理数据。将若干个元素看作一个数组的情况,称为一维数组。而将数组中的元素也可以为另一个数组。因此这种将数组作为元素的情况,称为二维数组,甚至多维数组等情况。下面就将对这些数组进行一一介绍。 5.2 一维数组   一维数组实际上是一组相同数据类型的信息集合。例如,学校的学生排列的一字长队就是一个数组。每一位学生都是数组中的一个元素。本节将介绍一维数组的创建及使用。   数组作为引用类型,允许使用new关键字进行内存分配。在使用数组之前,必须首先定义数组变量所属的类型。一维数组的创建有两种形式。   1. 先声明,再用new关键字进行内存分配 数据类型[] 数组名;   例如: int[] arr1;   数据类型决定了数组中元素的数据类型。它可以是在C#中任意的数据类型,数组名为一个合法的标识符符号。“[]”表示当前类型是数组,单个“[]”表示要创建的数组是一维数组。   声明数组后,还不能访问它的任何元素。因为声明数组,只是给出了数组名字和元素的数据类型。当只是声明数组之后,编译器会在内存的栈区找一个内存区域,将当前的数组名保存起来,其内存区域如图?5.3?所示。然后这块区域会保存真正存储了所有元素所在的位于内存堆上的地址。因此想要真正使用数组,还要为它分配内存空间。在为数组分配内存空间时,必须指明数组的长度,为数组分配内存空间的语法格式如下: 数组名 = new 数据类型[长度];   例如: arr1 = new int[10];   通过上面的语法可知,使用new关键字分配数组时,必须指定数组元素类型和元素的 图5.3 一维数组的内存区域 个数,即数组的长度。使用new关键字为数组分配内存时,整型数组中各个元素的初始值都为0。   回忆一下:每一个int型的变量所占的内存大小是多少?   在上面的示例中,arr1这一个数组分配了10个大小为int型的内存空间,且这些空间是连续的。   2. 声明的同时为数组分配内存   这种创建数组的方法是将数组的声明和内存的分配合并在一起执行。语法如下: 数据元素类型[]??数组名 = new 数据类型[数组长度]   例如: int[] arr1 = new int[10]; //定义一个名为arr1的int型数组,其最多容纳10个元素。 5.2.1 一维数组初始化   数组的初始化主要分为两种:为单个元素赋值和同时为整个数组赋值。下面分别介绍。   1. 为单个元素赋值   在声明一个数组并为其指定长度后,就可以通过数组元素的下标来访问每个元素,并为这些元素赋值。例如: int[] arr = new int[5]; //数组长度为5 arr[0] = 1; //数组下标从0开始,即下标为0的为第1个元素 arr[1] = 2; arr[2] = 3; arr[3] = 4; arr[4] = 5; //数组元素的最大下标为4   利用这种方法,可以依次为每一个元素进行赋值。但如果数组的长度较大时,则会使程序显得很冗长。如果存入数组的所有元素的值是有一定规律的,则可以使用循环来完成这一赋值过程。例如: int[] arr = new int[5]; for( int i = 0; i 9 || !(isColumn?&&?isRow?&&?isGrid)); 26 } 27 if (result) 28 Console.WriteLine("正确"); 29 else 30 Console.WriteLine("错误"); 31 Console.ReadKey(); 32 } 33 }   上述代码利用多重循环完成对二维数组中元素的检查,最终完成判定。读者可以进一步思考,考虑如何提高判定效率。 5.4 不规则数组(交错数组)   前面讲的二维数组都是规则的矩阵形数组,即每行具有相同的列数。但实际情况是,有时候每一行的列数是不同的。这样的二维数组实际是一个不规则型的数组。不规则型数组也有二维和多维之分。定义二维不规则数组时,使用两个中括号“[][]”;如果是定义三维不规则数组,则使用3个中括号“[][][]”,以此类推。以二维不规则数组为例,其定义方式如下: int[][] myarr = new int[3][];//定义一个int类型的二维不规则数组 myarr[0] = new int[5];//为第1行分配5个元素 myarr[1] = new int[3];//为第2行分配3个元素 myarr[2] = new int[4];//为第3行分配4个元素   因此上面代码中定义的不规则二维数组的空间占用如图5.6所示。   对于不规则数组而言,当每一维度的长度都相同时,也就变成了规则数组。因此规则数组上的所有操作对于不规则数组都是成立的。但对于不规则数组,在初始化时,必须为每一维数组元素进行赋值。   以不规则的二维数组为例,首先需要定义这个不规则二维数组,然后将每一行初始化为一个一维数组。例如: int[][] myarr = new int[3][];//定义一个int类型的二维不规则数组 myarr[0] = new int[]{0,1};//初始化第1行 myarr[1] = new int[]{0,1,2,3};//初始化第2行   在不规则的数组中,由于每一维都是一个单独的数组,因此可以通过行下标来获取指定行的列维数,如:myarr[0].Length可以获得myarr这个不规则数组的第1行的列数。例如,如代码5.3所示,可以通过循环为不规则数组进行初始化。 代码5.3 通过循环为不规则数组进行初始化示例代码 01 using System; 02 namespace Hello_World 03 { 04 class Program 05 { 06 static void Main(string[] args) 07 { 08 int[][] arr = new int[3][]; //声明不规则数组 09 arr[0] = new int[5]; 10 arr[1] = new int[3]; 11 arr[2] = new int[4]; 12 for(int i = 0; i