11-数组
数组是一种数据结构,用于存储相同类型的多个元素。数组在内存中是连续存储的,通过索引访问元素,具有极高的访问效率。
一、数组的声明和初始化
声明数组
csharp
// 方式一:声明后初始化
int[] numbers; // 声明(未分配内存)
numbers = new int[5]; // 初始化:分配 5 个元素的空间,默认值为 0
// 方式二:声明并初始化
int[] arr1 = new int[3]; // 默认值:{0, 0, 0}
int[] arr2 = new int[] { 1, 2, 3 }; // 初始化器
int[] arr3 = { 1, 2, 3 }; // 简化语法(编译器推断类型)
var arr4 = new int[] { 1, 2, 3 }; // 使用 var数组默认值
| 元素类型 | 默认值 |
|---|---|
| 数值类型(int, double 等) | 0 |
| bool | false |
| char | '\0' |
| 引用类型(string 等) | null |
csharp
int[] intArr = new int[3]; // {0, 0, 0}
bool[] boolArr = new bool[3]; // {false, false, false}
string[] strArr = new string[3]; // {null, null, null}二、数组的访问和遍历
通过索引访问
索引从 0 开始,最大索引为 Length - 1。
csharp
int[] arr = { 10, 20, 30, 40, 50 };
// 读取
Console.WriteLine(arr[0]); // 输出:10
Console.WriteLine(arr[4]); // 输出:50
// 修改
arr[1] = 25;
Console.WriteLine(arr[1]); // 输出:25
// 越界访问
// Console.WriteLine(arr[5]); // IndexOutOfRangeException:索引超出范围遍历数组(三种方式对比)
csharp
int[] arr = { 10, 20, 30, 40, 50 };
// 方式一:for 循环——需要索引时使用
for (int i = 0; i < arr.Length; i++)
{
Console.WriteLine($"arr[{i}] = {arr[i]}");
}
// 方式二:foreach 循环——不需要索引,更简洁
foreach (int item in arr)
{
Console.WriteLine(item);
}
// 方式三:while 循环——不常用
int index = 0;
while (index < arr.Length)
{
Console.WriteLine(arr[index]);
index++;
}for 与 foreach 对比
| 对比项 | for | foreach |
|---|---|---|
| 是否需要索引 | 是 | 否 |
| 能否修改元素 | 能(通过索引) | 不能(迭代变量只读) |
| 能否反向遍历 | 能 | 不能 |
| 可读性 | 一般 | 好 |
| 适用场景 | 需要索引、修改元素 | 只读遍历所有元素 |
三、多维数组
矩形二维数组
每一行的列数相同,在内存中连续存储。
csharp
// 声明方式
int[,] matrix = new int[3, 4]; // 3行4列
// 初始化
int[,] matrix = {
{ 1, 2, 3, 4 },
{ 5, 6, 7, 8 },
{ 9, 10, 11, 12 }
};
// 访问
Console.WriteLine(matrix[0, 0]); // 第一行第一列:1
Console.WriteLine(matrix[1, 2]); // 第二行第三列:7
// 遍历
int rows = matrix.GetLength(0); // 行数:3
int cols = matrix.GetLength(1); // 列数:4
for (int i = 0; i < rows; i++)
{
for (int j = 0; j < cols; j++)
{
Console.Write($"{matrix[i, j]}\t");
}
Console.WriteLine();
}三维数组
csharp
// 2 层 × 3 行 × 4 列
int[,,] cube = new int[2, 3, 4];
Console.WriteLine(cube.Rank); // 维度:3
Console.WriteLine(cube.GetLength(0)); // 第一维:2
Console.WriteLine(cube.GetLength(1)); // 第二维:3
Console.WriteLine(cube.GetLength(2)); // 第三维:4矩形数组 vs 交错数组
| 对比项 | 矩形数组 [,] | 交错数组 [][] |
|---|---|---|
| 子数组长度 | 所有行长度相同 | 每行长度可以不同 |
| 内存布局 | 连续一块 | 每行独立分配 |
| 初始化 | new int[3,4] | new int[3][],每行再 new |
| 访问语法 | arr[i,j] | arr[i][j] |
| 性能 | 较好(连续内存) | 稍差(多次间接访问) |
四、交错数组(锯齿数组)
数组的每个元素又是一个数组,且子数组长度可以不同。
csharp
// 声明
int[][] jagged = new int[3][];
// 初始化每个子数组(长度可以不同)
jagged[0] = new int[] { 1, 2 }; // 长度 2
jagged[1] = new int[] { 3, 4, 5 }; // 长度 3
jagged[2] = new int[] { 6, 7, 8, 9 }; // 长度 4
// 访问
Console.WriteLine(jagged[0][1]); // 第一个数组第二个元素:2
Console.WriteLine(jagged[2][3]); // 第三个数组第四个元素:9
// 遍历
for (int i = 0; i < jagged.Length; i++)
{
Console.Write($"第{i}行:");
for (int j = 0; j < jagged[i].Length; j++)
{
Console.Write($"{jagged[i][j]} ");
}
Console.WriteLine();
}五、Array 类的静态方法
System.Array 类提供了丰富的静态方法操作数组。
排序和反转
csharp
int[] arr = { 5, 2, 8, 1, 9 };
Array.Sort(arr); // 升序排序:{1, 2, 5, 8, 9}
Array.Reverse(arr); // 反转:{9, 8, 5, 2, 1}(Sort 后再 Reverse 可得到降序)查找
csharp
int[] arr = { 3, 7, 1, 9, 4, 7, 2 };
// IndexOf:查找第一个匹配项的索引
int idx1 = Array.IndexOf(arr, 7); // 1(第一个 7 的位置)
int idx2 = Array.IndexOf(arr, 99); // -1(未找到)
// LastIndexOf:从后查找
int idx3 = Array.LastIndexOf(arr, 7); // 5(最后一个 7 的位置)
// Exists:检查是否存在
bool hasEven = Array.Exists(arr, x => x % 2 == 0); // true
// Find:查找第一个匹配
int first = Array.Find(arr, x => x > 5); // 7
// FindAll:查找所有匹配
int[] all = Array.FindAll(arr, x => x > 5); // {7, 9, 7}
// FindIndex:查找第一个匹配的索引
int idx = Array.FindIndex(arr, x => x > 5); // 1
// TrueForAll:是否全部满足
bool allPositive = Array.TrueForAll(arr, x => x > 0); // true复制和调整
csharp
int[] source = { 1, 2, 3, 4, 5 };
int[] dest = new int[5];
// Copy:复制元素
Array.Copy(source, dest, source.Length); // {1, 2, 3, 4, 5}
// Clone:返回副本
int[] cloned = (int[])source.Clone();
Console.WriteLine(cloned == source); // False(不同引用)
// Clear:清空指定范围
Array.Clear(source, 1, 3); // {1, 0, 0, 0, 5}
// Resize:调整大小(可能创建新数组)
Array.Resize(ref source, 8); // {1, 0, 0, 0, 5, 0, 0, 0}
Array.Resize(ref source, 3); // {1, 0, 0}(截断)六、数组的局限性
| 局限 | 说明 | 替代方案 |
|---|---|---|
| 长度固定 | 创建后不能增删元素 | List<T> |
| 类型固定 | 只能存储声明时的类型 | ArrayList 或 object[] |
| 插入/删除不便 | 中间操作需要移动大量元素 | LinkedList<T> |
| 查找不便 | 需要遍历或使用 Array 静态方法 | Dictionary<K,V> |
csharp
// 数组长度不可变的示例
int[] arr = { 1, 2, 3 };
// 需要添加元素时,只能创建新数组
int[] newArr = new int[4];
Array.Copy(arr, newArr, arr.Length);
newArr[3] = 4;
arr = newArr; // 重新赋值七、数组实用技巧
数组转字符串
csharp
int[] arr = { 1, 2, 3 };
string str1 = string.Join(", ", arr);
Console.WriteLine(str1); // 1, 2, 3
string str2 = string.Join(" | ", arr.Select(x => $"[{x}]"));
Console.WriteLine(str2); // [1] | [2] | [3]数组转 List
csharp
int[] arr = { 1, 2, 3 };
List<int> list = arr.ToList();
list.Add(4); // List 可以动态增长初始化特定值的数组
csharp
// 全部初始化为同一个值
int[] zeros = new int[10]; // 全部为 0(默认)
int[] fives = Enumerable.Repeat(5, 10).ToArray(); // 全部为 5
// 生成连续序列
int[] sequence = Enumerable.Range(1, 10).ToArray(); // {1, 2, 3, ..., 10}
// 生成随机数组
Random rnd = new Random();
int[] randomArr = Enumerable.Range(0, 10).Select(_ => rnd.Next(1, 100)).ToArray();八、综合案例
案例:学生成绩分析
csharp
static void Main()
{
int[] scores = { 85, 92, 78, 63, 95, 88, 72, 59, 100, 81 };
// 排序
Array.Sort(scores);
// 基本信息
Console.WriteLine($"学生人数:{scores.Length}");
Console.WriteLine($"最低分:{scores[0]}");
Console.WriteLine($"最高分:{scores[scores.Length - 1]}");
// 平均分
double avg = scores.Average();
Console.WriteLine($"平均分:{avg:F1}");
// 找出及格和不及格
int[] passed = Array.FindAll(scores, s => s >= 60);
int[] failed = Array.FindAll(scores, s => s < 60);
Console.WriteLine($"及格人数:{passed.Length}({passed.Length * 100.0 / scores.Length:F1}%)");
Console.WriteLine($"不及格人数:{failed.Length}({failed.Length * 100.0 / scores.Length:F1}%)");
// 统计各分数段
int[] levels = { 0, 60, 70, 80, 90, 101 };
string[] levelNames = { "不及格", "及格", "中等", "良好", "优秀" };
for (int i = 0; i < levelNames.Length; i++)
{
int count = Array.FindAll(scores, s => s >= levels[i] && s < levels[i + 1]).Length;
Console.WriteLine($"{levelNames[i]}:{count} 人");
}
}核心知识点总结
数组创建方式速查
csharp
int[] a1 = new int[3]; // 指定长度,默认值
int[] a2 = new int[] { 1, 2, 3 }; // 初始化器
int[] a3 = { 1, 2, 3 }; // 简化语法
int[,] a4 = new int[2, 3]; // 二维矩形数组
int[][] a5 = new int[3][]; // 交错数组注意事项
- 索引从 0 开始,有效范围
0 ~ Length-1 - 越界异常:访问超出范围的索引会抛出
IndexOutOfRangeException - 数组是引用类型:赋值给另一个变量时传递的是引用(不是副本)csharp
int[] a = { 1, 2, 3 }; int[] b = a; // b 和 a 指向同一个数组 b[0] = 100; Console.WriteLine(a[0]); // 输出:100(被 b 修改了) // 如需独立副本: int[] c = (int[])a.Clone(); - 数组长度不可变:需要动态长度时使用
List<T> Array.Sort会修改原数组:如需保留原数组,先复制再排序


