C#开发者必学之数组基础知识精讲
数组是C#编程中最基础且最重要的数据结构之一。无论你是初学者还是有经验的开发者,深入理解数组的原理和用法都至关重要。本文将全面、详细地讲解C#数组的各个方面,旨在帮助你牢固掌握这一核心概念。
1. 什么是数组?
数组是一种线性数据结构,它在内存中连续存储相同类型的多个元素。你可以把数组想象成一排整齐排列的盒子,每个盒子里都装着相同类型的数据(例如,整数、字符串、对象等)。每个盒子都有一个唯一的编号,称为索引(或下标),我们可以通过索引来快速访问数组中的特定元素。
关键特性:
- 同类型元素: 数组中的所有元素必须是相同的数据类型。 例如,一个整数数组只能存储整数,不能存储字符串或浮点数。
- 连续内存: 数组的元素在内存中是连续存储的,这意味着它们在内存地址上是相邻的。这种连续性使得数组可以进行高效的随机访问。
- 固定大小: C#中的传统数组(
[]
)在创建时必须指定大小,并且一旦创建,其大小就不能更改。 (注意:List<T>
等集合类型提供了可变大小的功能,但它们不是本文讨论的重点。) - 索引访问: 可以通过元素的索引(从0开始的整数)来访问数组中的元素。例如,
myArray[0]
表示访问数组myArray
的第一个元素。
2. 数组的声明和初始化
在C#中,声明和初始化数组有多种方式。
2.1 声明数组
声明数组时,需要指定数组的数据类型和数组名,并在数组名后加上一对方括号 []
。
“`csharp
// 声明一个整数数组
int[] numbers;
// 声明一个字符串数组
string[] names;
// 声明一个自定义类(例如 Person)的数组
Person[] people;
“`
2.2 初始化数组
初始化数组是指为数组分配内存空间并(可选地)为数组元素赋初值。
方法 1:声明时初始化
“`csharp
// 声明并初始化一个包含 5 个整数的数组
int[] numbers = { 1, 2, 3, 4, 5 };
// 声明并初始化一个包含 3 个字符串的数组
string[] names = { “Alice”, “Bob”, “Charlie” };
//使用new关键字创建对象
int[] numbers2 = new int[] {1,2,3};
“`
方法 2:声明后用 new
关键字初始化
“`csharp
// 声明一个整数数组
int[] numbers;
// 使用 new 关键字初始化数组,指定数组大小为 5
numbers = new int[5]; // 数组元素会被初始化为默认值(整数的默认值为 0)
// 声明一个字符串数组
string[] names;
names = new string[3]; //数组元素会被初始化成默认值(字符串的默认值是null)
// 声明后用 new 关键字初始化并赋值
double[] values = new double[3] { 1.5, 2.7, 3.1 };
“`
方法3:隐式类型数组(var)
C# 3.0 及更高版本引入了隐式类型数组,允许编译器根据初始化表达式推断数组类型。
csharp
var implicitArray = new[] { 1, 2, 3, 4, 5 }; // 编译器推断为 int[]
var stringArray = new[] { "hello", "world" }; // 编译器推断为 string[]
注意:
- 使用
new
关键字初始化数组时,必须指定数组的大小。 - 如果声明时没有立即初始化数组,则必须使用
new
关键字来分配内存空间。 - 数组元素会被初始化为相应数据类型的默认值(例如,整数的默认值为 0,字符串的默认值为
null
,布尔值的默认值为false
)。
3. 访问数组元素
数组元素是通过索引(下标)来访问的。索引是从 0 开始的整数,表示元素在数组中的位置。
“`csharp
int[] numbers = { 10, 20, 30, 40, 50 };
// 访问第一个元素(索引为 0)
int firstNumber = numbers[0]; // firstNumber 的值为 10
// 访问第三个元素(索引为 2)
int thirdNumber = numbers[2]; // thirdNumber 的值为 30
// 修改第二个元素的值(索引为 1)
numbers[1] = 25;
// 访问修改后的第二个元素
Console.WriteLine(numbers[1]); // 输出 25
“`
越界访问:
访问数组元素时,必须确保索引在有效范围内(0 到 数组长度 - 1
)。如果尝试访问超出范围的索引,将会引发 IndexOutOfRangeException
异常。
“`csharp
int[] numbers = { 1, 2, 3 };
// 尝试访问索引为 3 的元素(越界)
// 这将引发 IndexOutOfRangeException 异常
// int invalidValue = numbers[3];
“`
4. 数组的长度
可以使用数组的 Length
属性获取数组的长度(即数组中元素的个数)。
“`csharp
int[] numbers = { 1, 2, 3, 4, 5 };
// 获取数组的长度
int length = numbers.Length; // length 的值为 5
Console.WriteLine(“数组的长度为: ” + length); // 输出:数组的长度为: 5
“`
Length
属性是一个只读属性,不能用于修改数组的大小。
5. 遍历数组
遍历数组是指逐个访问数组中的每个元素。常用的遍历方法有:
5.1 使用 for
循环
“`csharp
int[] numbers = { 1, 2, 3, 4, 5 };
// 使用 for 循环遍历数组
for (int i = 0; i < numbers.Length; i++)
{
Console.WriteLine(“索引 ” + i + ” 的元素值为: ” + numbers[i]);
}
“`
5.2 使用 foreach
循环
foreach
循环提供了一种更简洁的遍历数组的方式,它不需要显式地使用索引。
“`csharp
int[] numbers = { 1, 2, 3, 4, 5 };
// 使用 foreach 循环遍历数组
foreach (int number in numbers)
{
Console.WriteLine(“元素值为: ” + number);
}
“`
for
循环和 foreach
循环的选择:
- 如果需要访问数组元素的索引,或者需要在循环中修改数组元素的值,则应使用
for
循环。 - 如果只需要读取数组元素的值,并且不需要索引,则可以使用
foreach
循环,它更简洁易读。
6. 多维数组
C# 支持多维数组,最常见的是二维数组(例如,表示矩阵或表格)。
6.1 二维数组的声明和初始化
“`csharp
// 声明一个 3×4 的二维整数数组
int[,] matrix = new int[3, 4];
// 声明并初始化一个 2×3 的二维字符串数组
string[,] names = {
{ “Alice”, “Bob”, “Charlie” },
{ “David”, “Emily”, “Frank” }
};
“`
6.2 访问二维数组元素
访问二维数组元素需要使用两个索引,分别表示行和列。
“`csharp
int[,] matrix = {
{ 1, 2, 3 },
{ 4, 5, 6 },
{ 7, 8, 9 }
};
// 访问第一行第二列的元素(索引为 [0, 1])
int element = matrix[0, 1]; // element 的值为 2
// 修改第二行第三列的元素的值(索引为 [1, 2])
matrix[1, 2] = 10;
“`
6.3 遍历二维数组
可以使用嵌套的 for
循环或 foreach
循环来遍历二维数组。
“`csharp
int[,] matrix = {
{ 1, 2, 3 },
{ 4, 5, 6 },
{ 7, 8, 9 }
};
// 使用嵌套的 for 循环遍历二维数组
for (int i = 0; i < matrix.GetLength(0); i++) // GetLength(0) 获取行数
{
for (int j = 0; j < matrix.GetLength(1); j++) // GetLength(1) 获取列数
{
Console.Write(matrix[i, j] + ” “);
}
Console.WriteLine();
}
// 使用嵌套的 foreach 循环遍历二维数组 (不常用,因为无法获取索引)
foreach (int element in matrix)
{
Console.Write(element + ” “);
}
“`
注意:
- 多维数组每一维度长度可以不同。
- 使用
GetLength()
方法可以获取指定维度的长度。
7. 交错数组 (Jagged Arrays)
交错数组是一种特殊的数组,它的每个元素又是一个数组,并且这些子数组的长度可以不同。
7.1 交错数组的声明和初始化
“`csharp
// 声明一个交错数组,包含 3 个子数组
int[][] jaggedArray = new int[3][];
// 初始化第一个子数组,长度为 2
jaggedArray[0] = new int[] { 1, 2 };
// 初始化第二个子数组,长度为 3
jaggedArray[1] = new int[] { 3, 4, 5 };
// 初始化第三个子数组,长度为 1
jaggedArray[2] = new int[] { 6 };
“`
7.2 访问交错数组元素
访问交错数组元素需要使用多个方括号。
“`csharp
int[][] jaggedArray = {
new int[] { 1, 2 },
new int[] { 3, 4, 5 },
new int[] { 6 }
};
// 访问第一个子数组的第二个元素(值为 2)
int element = jaggedArray[0][1];
// 修改第二个子数组的第三个元素的值
jaggedArray[1][2] = 7;
“`
7.3 遍历交错数组
可以使用嵌套的 for
循环或 foreach
循环来遍历交错数组。
“`csharp
int[][] jaggedArray = {
new int[] { 1, 2 },
new int[] { 3, 4, 5 },
new int[] { 6 }
};
// 使用嵌套的 for 循环遍历交错数组
for (int i = 0; i < jaggedArray.Length; i++)
{
for (int j = 0; j < jaggedArray[i].Length; j++)
{
Console.Write(jaggedArray[i][j] + ” “);
}
Console.WriteLine();
}
// 使用嵌套的 foreach 循环遍历交错数组
foreach (int[] subArray in jaggedArray)
{
foreach (int element in subArray)
{
Console.Write(element + ” “);
}
Console.WriteLine();
}
“`
多维数组 vs. 交错数组:
- 多维数组: 矩形结构,所有行的长度相同。
- 交错数组: 每一行可以有不同的长度。
8. 数组的常用方法
C# 的 System.Array
类提供了一些有用的静态方法来操作数组。
8.1 Array.Sort()
Array.Sort()
方法用于对数组进行排序(升序)。
“`csharp
int[] numbers = { 5, 2, 8, 1, 9, 4 };
// 对数组进行排序
Array.Sort(numbers);
// 输出排序后的数组
foreach (int number in numbers)
{
Console.Write(number + ” “); // 输出:1 2 4 5 8 9
}
“`
8.2 Array.Reverse()
Array.Reverse()
方法用于反转数组中元素的顺序。
“`csharp
int[] numbers = { 1, 2, 3, 4, 5 };
// 反转数组
Array.Reverse(numbers);
// 输出反转后的数组
foreach (int number in numbers)
{
Console.Write(number + ” “); // 输出:5 4 3 2 1
}
“`
8.3 Array.IndexOf()
Array.IndexOf()
方法用于查找指定元素在数组中第一次出现的索引。如果未找到,则返回 -1。
“`csharp
int[] numbers = { 10, 20, 30, 40, 50 };
// 查找元素 30 的索引
int index = Array.IndexOf(numbers, 30); // index 的值为 2
// 查找不存在的元素 60 的索引
int notFoundIndex = Array.IndexOf(numbers, 60); // notFoundIndex 的值为 -1
“`
8.4 Array.Copy()
Array.Copy()
方法用于将一个数组的一部分或全部复制到另一个数组。
“`csharp
int[] sourceArray = { 1, 2, 3, 4, 5 };
int[] destinationArray = new int[3];
// 将 sourceArray 的前 3 个元素复制到 destinationArray
Array.Copy(sourceArray, destinationArray, 3);
// 输出 destinationArray
foreach (int number in destinationArray)
{
Console.Write(number + ” “); // 输出:1 2 3
}
“`
8.5 Array.Clear()
Array.Clear()
方法用于将数组中指定范围的元素设置为其数据类型的默认值.
“`csharp
int[] numbers = { 1, 2, 3, 4, 5 };
// 将索引从 1 到 3(不包括 3)的元素清零
Array.Clear(numbers, 1, 2);
// 输出清零后的数组
foreach (int number in numbers)
{
Console.Write(number + ” “); // 输出:1 0 0 4 5
}
“`
9. 数组作为方法参数和返回值
数组可以作为方法的参数传递,也可以作为方法的返回值。
9.1 数组作为参数
“`csharp
// 方法:计算数组中所有元素的总和
public static int SumArray(int[] arr)
{
int sum = 0;
foreach (int number in arr)
{
sum += number;
}
return sum;
}
// 调用方法
int[] numbers = { 1, 2, 3, 4, 5 };
int total = SumArray(numbers); // total 的值为 15
Console.WriteLine(total);
“`
9.2 数组作为返回值
“`csharp
// 方法:创建一个包含指定范围内整数的数组
public static int[] CreateRangeArray(int start, int end)
{
int[] result = new int[end – start + 1];
for (int i = 0; i < result.Length; i++)
{
result[i] = start + i;
}
return result;
}
// 调用方法
int[] myArray = CreateRangeArray(5, 10);
// 输出数组
foreach (int number in myArray)
{
Console.Write(number + ” “); // 输出:5 6 7 8 9 10
}
“`
注意:
- 当数组作为参数传递给方法时,传递的是数组的引用(地址),而不是数组的副本。这意味着在方法内部对数组的修改会影响到原始数组。
- 如果希望在方法内部修改数组,但不影响原始数组,可以先创建一个数组的副本,然后在方法内部操作副本。可以使用
Array.Copy()
方法创建副本。
10. 总结
数组是C#编程中不可或缺的基础数据结构。本文详细介绍了数组的声明、初始化、访问、遍历、多维数组、交错数组、常用方法以及数组作为方法参数和返回值的用法。
掌握数组的这些核心知识,将为你在C#编程中处理各种数据集合打下坚实的基础。请务必通过实践来巩固所学知识,编写各种涉及数组操作的代码,加深理解。
希望本文能帮助你更好地理解和运用C#数组!