|
|
51CTO旗下网站
|
|
移动端

2.7.3 数组的使用

《C# 6.0本质论(第5版)》第2章数据类型,本章将探讨这些数据类型,更深入地研究字符串类型,并引入数组的概念。本节为大家介绍数组的使用。

作者:周靖/庞燕 译来源:人民邮电出版社|2017-07-21 16:53

2.7.3 数组的使用

可以使用方括号表示法,也就是所谓的数组访问符(array accessor),来访问数组中一个特定的数据项。为了获取数组的第一个数据项,要指定0作为索引。在代码清单2-44中,我们将languages变量中的第5项(其索引为4,因为第一项的索引是0)的值存储到变量language中。

代码清单2-44 声明并访问数组

  1. string[] languages = new string[9]{  
  2. "C#", "COBOL", "Java",  
  3. "C++", "Visual Basic", "Pascal",  
  4. "Fortran", "Lisp", "J#"};  
  5. // Retrieve fifth item in languages array (Java)  
  6. string language = languages[4]; 


方括号表示法还用于将数据存储到数组中。代码清单2-45交换了"C++"和"Java"的顺序。

代码清单2-45 交换数组中不同位置的数据

  1. string[] languages = new string[9]{  
  2. "C#", "COBOL", "Java",  
  3. "C++", "Visual Basic", "Pascal",  
  4. "Fortran", "Lisp", "J#"};  
  5. // Save "C++" to variable called language.  
  6. string language = languages[3];  
  7. // Assign "Java" to the C++ position.  
  8. languages[3] = languages[2];  
  9. // Assign language to location of "Java".  
  10. languages[2] = language; 

在多维数组中,元素是用每个维上的一个索引来标识的,如代码清单2-46所示。

代码清单2-46 初始化二维整数数组

  1. int[,] cells = {  
  2. {1, 0, 2},  
  3. {0, 2, 0},  
  4. {1, 2, 1}  
  5. };  
  6. // Set the winning tic-tac-toe move to be player 1.  
  7. cells[1,0] = 1; 

交错数组元素的赋值稍微有所不同,这是因为它必须与交错数组的声明保持一致。第一个索引指定了“由数组构成的数组”中的一个数组。第二个索引则指定了是该数组中的哪一项(参见代码清单2-47)。

代码清单2-47 声明一个交错数组

  1. int[][] cells = {  
  2. new int[]{1, 0, 2},  
  3. new int[]{0, 2, 0},  
  4. new int[]{1, 2, 1}  
  5. };  
  6. cells[1][0] = 1;  
  7. // ... 

1. 长度

像代码清单2-48那样获取数组的长度。

代码清单2-48 获取数组的长度

  1. Console.WriteLine(  
  2. $"There are { languages.Length } languages in the array."); 

数组的长度是固定的,不能随便更改,除非重新创建数组。除此之外,越过数组的边界(或长度)会造成“运行时”报错。用无效索引(索引指向的元素不存在)来访问(检索或者赋值)数组时,就会发生这种情况。例如,在代码清单2-49中,如果用数组长度作为索引来访问数组就会出错。

代码清单2-49 访问超过数组的边界会引发异常

  1. string languages = new string[9];  
  2. ...  
  3. // RUNTIME ERROR: index out of bounds – should  
  4. // be 8 for the last element  
  5. languages[4] = languages[9]; 

注意

Length成员返回数组中数据项的个数,而不是返回最高的索引值。languages变量的Length成员是9,而languages变量的最高索引是8,那是从起点能到达的最远的一个位置。

比较好的做法是使用Length代替硬编码的数组大小。例如,为了将Length作为索引来使用,有必要在它上面减1,以避免越界错误,如代码清单2-50所示。

代码清单2-50 在数组索引中使用Length-1

  1. string languages = new string[9];  
  2. ...  
  3. languages[4] = languages[languages.Length - 1]; 

为了避免越过数组边界,应使用长度检查来验证数组的长度大于0。在访问数组中的最后一项时,要像代码清单2-50那样,使用Length-1而不是硬编码的值。

Length返回数组中元素的总数。因此,如果你有一个多维数组,比如大小为2×3×3的bool cells[,,]数组,那么Length会返回元素总数18。

对于交错数组,Length返回的是外部数组的元素数。因为交错数组是“数组构成的数组”,所以Length只作用于外部数组,只统计它的元素数(也就是具体由多少个数组构成),而不管各内部数组共包含了多少个元素。

语言对比:C++ —缓冲区溢出错误

非托管的C++并非总是检查是否越过数组的边界。这个错误不仅很难调试,而且有可能造成潜在的安全问题,也就是所谓的缓冲区溢出(buffer overrun)。相反,CLR能防止所有C#(和托管C++)代码越过数组边界,消除了在托管代码中发生缓冲区溢出的可能。

2. 更多的数组方法

数组提供了更多的方法来操纵数组中的元素,例如Sort()、BinarySearch()、Reverse()和Clear()等,如代码清单2-51所示。

代码清单2-51 更多的数组方法

  1. class ProgrammingLanguages  
  2. {  
  3. static void Main()  
  4. {  
  5. string[] languages = new string[]{  
  6. "C#", "COBOL", "Java",  
  7. "C++", "Visual Basic", "Pascal",  
  8. "Fortran", "Lisp", "J#"};  
  9. System.Array.Sort(languages);  
  10. string searchString = "COBOL";  
  11. int index = System.Array.BinarySearch(  
  12. languages, searchString);  
  13. System.Console.WriteLine(  
  14. "The wave of the future, "  
  15. + $"{ searchString }, is at index { index }.");  
  16. System.Console.WriteLine();  
  17. System.Console.WriteLine(  
  18. $"{ "First Element",-20 }\t{ "Last Element",-20 }");  
  19. System.Console.WriteLine(  
  20. $"{ "-------------",-20 }\t{ "------------",-20 }");  
  21. System.Console.WriteLine(  
  22. $"{ languages[0],-20 }\t{ languages[languages.Length-1],-20 }");  
  23. System.Array.Reverse(languages);  
  24. System.Console.WriteLine(  
  25. $"{ languages[0],-20 }\t{ languages[languages.Length-1],-20 }");  
  26. // Note this does not remove all items from the array.  
  27. // Rather it sets each item to the type’s default value.  
  28. System.Array.Clear(languages, 0, languages.Length);  
  29. System.Console.WriteLine(  
  30. $"{ languages[0],-20 }\t{ languages[languages.Length-1],-20 }");  
  31. System.Console.WriteLine(  
  32. $"After clearing, the array size is: { languages.Length }");  
  33. }  

输出2-20展示了结果。

输出2-20

  1. The wave of the future, COBOL, is at index 2.  
  2. First Element Last Element  
  3. ------------- ------------  
  4. C# Visual Basic  
  5. Visual Basic C#  
  6. After clearing, the array size is: 9 

这些方法由System.Array类提供。大多数方法都是一目了然的。只需注意以下两点。

使用BinarySearch()方法前要对数组进行排序。如果值不按升序排序,会返回不正确的索引。搜索的元素不存在,会返回负值。使用取反操作符~index,会返回大于搜索值的第一个索引(如果有的话)。

Clear()方法不删除数组元素,而且不将长度设为零。数组大小是固定的,不能修改。所以,Clear()方法将数组中的每个元素都设为其默认值(false、0或者null)。这解释了在调用Clear()之后输出数组时,Console.WriteLine()为什么会创建一个空行。语言对比:Visual Basic —允许改变数组的维

Visual Basic提供了Redim语句来更改数组中的元素个数。虽然没有等价的C#关键字,但.NET 2.0提供了Resize()方法来重新创建数组,并将所有元素复制到新数组。这个方法称为System.Array.Resize。

3. 数组实例方法

类似于字符串,数组也有一些实例成员,它们不是从数据类型访问,而是直接从变量中访问。Length就是实例成员,因为是通过数组变量来访问Length,而不是通过类。其他常用实例成员还有GetLength()、Rank和Clone()。

要获取特定维的长度不是使用Length属性,而是使用数组的GetLength()实例方法。调用该方法时要指定返回哪一维的长度,如代码清单2-52所示。

代码清单2-52 获取特定维的大小

  1. bool[,,] cells;  
  2. cells = new bool[2,3,3];  
  3. System.Console.WriteLine(cells.GetLength(0)); // Displays 2 

结果如输出2-21所示。

输出2-21


代码清单2-51输出2,这是第一维上的元素个数。

还可以访问数组的Rank成员来获取整个数组的维数。例如,cells.Rank返回3。

默认情况下,将一个数组变量赋值给另一个数组变量只会复制数组引用,而不是数组中单独的元素。要创建数组的全新副本,需使用数组的Clone()方法。该方法返回数组的一个副本,更改这个新数组中的任何成员都不会影响原始数组的成员。

喜欢的朋友可以添加我们的微信账号:

51CTO读书频道二维码


51CTO读书频道活动讨论群:342347198

【责任编辑:book TEL:(010)68476606】

回书目   上一节   下一节
点赞 0
分享:
大家都在看
猜你喜欢

读 书 +更多

XML基础教程

本书分为8章。第1章主要对XML做了简单的介绍。第2章详细讲解规范的XML文件。第3章主要讲解有效的XML文件,特别重点讲解DTD文件。第4章讲解C...

订阅51CTO邮刊

点击这里查看样刊

订阅51CTO邮刊