任务二 多维数组
一、多维数组是什么?
- 多维数组,即Multidimensional Arrays
- 是一种可以存储数据在多个维度(例如行和列,或者更多维度)的数据结构。
- 最常见的多维数组是*二维数组(2D):类似表格,有行和列。
- C# 也支持三维数组(3D):可以想象为一个立方体,有长、宽、高。
- 更高维度的数组理论上也是支持的,但实际开发中使用较少。
声明二维数组的语法
1. 声明但不初始化(元素为默认值)
数据类型[,] 数组名;
示例:
int[,] matrix;
string[,] grid;
2. 声明并指定维度大小(不赋初值)
数据类型[,] 数组名 = new 数据类型[行数, 列数];
示例:
int[,] matrix = new int[3, 4]; // 3行4列,元素均为0
3. 声明时直接初始化(隐式维度)
数据类型[,] 数组名 = { { 值00, 值01, ... }, { 值10, 值11, ... }, ... };
示例:
int[,] matrix = { { 1, 2, 3 }, { 4, 5, 6 } };
4. 声明 + new + 直接初始化(显式维度)
数据类型[,] 数组名 = new 数据类型[行数, 列数] { { ... }, { ... }, ... };
示例:
int[,] matrix = new int[2, 3] { { 1, 2, 3 }, { 4, 5, 6 } };
5. 使用 var 关键字(必须直接初始化)
var 数组名 = new 数据类型[,] { { ... }, { ... } };
或
var 数组名 = new[,] { { ... }, { ... } };
示例:
var matrix = new[,] { { 1, 2 }, { 3, 4 } };
二、初始化二维数组的语法(单独赋值)
1. 声明后逐一赋值
数组名[行索引, 列索引] = 值;
示例:
int[,] matrix = new int[2, 2];
matrix[0, 0] = 10;
matrix[0, 1] = 20;
matrix[1, 0] = 30;
matrix[1, 1] = 40;
2. 使用嵌套循环批量赋值
for (int i = 0; i < 行数; i++)
for (int j = 0; j < 列数; j++)
数组名[i, j] = 表达式;
示例:
int[,] matrix = new int[3, 3];
for (int i = 0; i < 3; i++)
for (int j = 0; j < 3; j++)
matrix[i, j] = i * 3 + j + 1;
3. 使用 Array.SetValue 方法
数组名.SetValue(值, 行索引, 列索引);
示例:
int[,] matrix = new int[2, 2];
matrix.SetValue(99, 0, 1);
三、常见示例汇总
| 语法类型 | 代码示例 |
|---|---|
| 声明+指定大小 | int[,] arr = new int[2, 3]; |
| 声明+直接初始化 | int[,] arr = { {1,2}, {3,4} }; |
| 声明+new+直接初始化 | int[,] arr = new int[2,2] { {1,2}, {3,4} }; |
| var 隐式类型 | var arr = new[,] { {1,2}, {3,4} }; |
| 后期逐个赋值 | arr[0,0] = 10; arr[0,1] = 20; |
如果需要以上内容转为 学生填空版(留空关键词语法)或 练习题,请告知。
二、二维数组(2D Array)
1. 定义与声明
二维数组的声明语法如下:
// 声明一个二维整型数组(未初始化)
int[,] twoDimensionalArray;
语法说明:使用 两个连续的方括号
[,]表示二维数组。
2. 初始化二维数组
方式一:声明并直接初始化(指定大小 + 赋值)
// 声明一个 2 行 3 列的二维数组,并初始化值
int[,] matrix = new int[2, 3]
{
{1, 2, 3}, // 第 0 行
{4, 5, 6} // 第 1 行
};
2是行数(第一个维度)3是列数(第二个维度)
方式二:先声明,后初始化(不推荐,一般直接初始化)
int[,] matrix; // 声明
matrix = new int[2, 3]; // 分配空间
// 然后再逐个赋值
matrix[0, 0] = 1;
matrix[0, 1] = 2;
matrix[0, 2] = 3;
matrix[1, 0] = 4;
// ...以此类推
3. 访问二维数组元素
通过指定 行索引 和 列索引 来访问:
int value = matrix[1, 2]; // 获取第2行第3列的值(从0开始)
Console.WriteLine(value); // 输出:6
4. 遍历二维数组
常用 for 循环 或 foreach 循环遍历二维数组:
使用 for 循环(推荐,可控制行列)
for (int i = 0; i < matrix.GetLength(0); i++) // 行数
{
for (int j = 0; j < matrix.GetLength(1); j++) // 列数
{
Console.Write(matrix[i, j] + "\t");
}
Console.WriteLine();
}
使用 foreach 循环(简单遍历,但不能获取索引)
foreach (int num in matrix)
{
Console.Write(num + " ");
}
// 输出:1 2 3 4 5 6
注意:
foreach不提供行列信息,仅用于顺序访问所有元素。
5. 获取二维数组的行数和列数
- GetLength(0):获取第一维大小(通常是行数)
- GetLength(1):获取第二维大小(通常是列数)
int rows = matrix.GetLength(0); // 行数
int cols = matrix.GetLength(1); // 列数
Console.WriteLine($"行数: {rows}, 列数: {cols}");
三、三维数组(3D Array)
1. 定义与初始化
语法使用 三个方括号 [, ,]:
// 声明一个 2x3x4 的三维数组
int[,,] threeDArray = new int[2, 3, 4];
// 或者直接初始化(比较复杂,一般较少这样写)
int[,,] cube = new int[2, 2, 2]
{
{
{1, 2},
{3, 4}
},
{
{5, 6},
{7, 8}
}
};
- 第一维:2
- 第二维:2
- 第三维:2
访问方式:
int val = cube[1, 0, 1]; // 获取第2个盒子、第1行、第2列的值
遍历三维数组通常需要三层嵌套循环,较为复杂,实际开发中较少使用。
四、锯齿数组(Jagged Array) vs 多维数组
⚠️ 注意:多维数组(如 int[,])不同于锯齿数组(Jagged Array,如 int[][])
| 特性 | 多维数组 (int[,], int[,,]) | 锯齿数组 (int[][], int[][][]) |
|---|---|---|
| 结构 | 所有“行”长度一致,是矩形 | 每“行”可以长度不同,是数组的数组 |
| 声明 | int[,]、int[,,] 等 | int[][]、int[][][] 等 |
| 灵活性 | 固定维度,每维大小一致 | 更灵活,每行/层可不同长度 |
| 性能 | 通常略好 | 稍慢,因为是数组嵌套 |
如果你的数据是“表格型”,每行列数相同,推荐使用多维数组; 如果每行数据长度可能不同,比如每个学生的成绩数量不同,用锯齿数组更合适。
五、多维数组的常用操作示例
示例 1:创建并打印一个 3x3 的二维数组
int[,] grid = new int[3, 3]
{
{1, 2, 3},
{4, 5, 6},
{7, 8, 9}
};
for (int i = 0; i < grid.GetLength(0); i++)
{
for (int j = 0; j < grid.GetLength(1); j++)
{
Console.Write(grid[i, j] + "\t");
}
Console.WriteLine();
}
示例 2:二维数组求和
int sum = 0;
for (int i = 0; i < matrix.GetLength(0); i++)
for (int j = 0; j < matrix.GetLength(1); j++)
sum += matrix[i, j];
Console.WriteLine("数组所有元素之和为: " + sum);
六、总结:C# 多维数组要点
| 项目 | 说明 |
|---|---|
| 二维数组声明 | int[,] array; |
| 二维数组初始化 | new int[行数, 列数] { {...}, {...} } |
| 访问元素 | array[行索引, 列索引] |
| 获取维度长度 | array.GetLength(0)(行)、array.GetLength(1)(列) |
| 遍历方式 | 嵌套 for 循环 或 foreach(无索引) |
| 三维及以上 | 使用 int[,,], int[,,,] 等,但较少用 |
| 与锯齿数组区别 | 多维数组是“矩形”,锯齿数组是“数组的数组”,每“行”可不同长 |
七、什么时候使用多维数组?
✅ 适合场景:
- 数据是规整的表格形式,比如矩阵、棋盘、地图格子等;
- 行列数固定且一致;
- 需要高效地按行列访问数据;
❌ 不适合场景:
- 每“行”数据长度不同(如每个学生选修课程数量不同)→ 使用锯齿数组(Jagged Array)
- 数据非常动态、频繁增删 → 考虑使用
List<List<T>>等集合类更灵活
八、扩展建议
如果你想进一步学习:
- 如何将二维数组以表格形式显示在控制台或 UI 中
- 如何实现二维数组的搜索、排序(比如按某列排序)
- 如何用多维数组处理游戏地图、图像像素等实际问题
欢迎继续提问,我可以为你提供具体示例代码!
是否需要我为你提供一个完整的控制台示例程序,比如一个 学生成绩二维表(多维数组)的增删查改 或 矩阵运算 的例子?
一、任务描述
学习二维数组的声明、初始化以及二维数组的输入输出。
二、预备知识
前面介绍的数组只有一个下标,称为一维数组,其数组元素称为单下标变量。在实际问题中有很多量是二维的或多维的,因此,C#语言允许构造多维数组。多维数组元素有多个下标,以标识它在数组中的位置,所以也称为多下标变量。
(一)声明多维数组
多维数组是指可以用多个下标访问的数组,声明时,方括号内加逗号,就表明是多维数组,有n个逗号,就是n+1维数组。下面以最常用的二维数组为例讲解多维数组的声明及初始化。
二维数组即数组的维数为2,二维数组类似于矩形网格和非矩形网格。在程序中通常使用二维数组来存储二维表中的数据,而二维数组其实就是一个基本的多维数组。 例如,表6-1举例说明了一个4行3列的二维数组的存储结构。
表6-1 二维数组的存储结构
| 数组索引 | [0,0] | [0,1] | [0,2] |
|---|---|---|---|
| [1,0] | [1,1] | [1,2] | |
| [2,0] | [2,1] | [2,2] | |
| [3,0] | [3,1] | [3,2] |
二维数组的声明语法如下:
type[,] arrayName
type:数组存储数据的数据类型。arrayName:数组名称。
例如,声明一个4行3列的整型二维数组,代码如下:
int[,] arr = new int[4,3]; //声明一个int类型的二维数组
此二维数组的存储结构见表6-1。
前面讲的都是行和列固定的矩形矩阵,如4×4,3×2等,C#中同时支持不规则的数组,在二维数组中,不同行的元素个数可以完全不相同,例如:
int[][] a = new int[3][]; //声明一个二维数组,只指定行数,不指定列数
a[0] = new int[5]; //第一行分配5个元素
a[1] = new int[3]; //第二行分配3个元素
a[2] = new int[4]; //第三行分配4个元素
这个不规则二维数组所占的空间见表6-2。
表6-2 不规则二维数组的存储结构
a[3][]→a[0]→ [□□□□□]a[1]→ [□□□]a[2]→ [□□□□]
(二)初始化多维数组
数组声明完之后,需要对其进行初始化,初始化数组有很多形式。
例如,通过new运算符创建二维数组,并将数组元素初始化为它们的默认值,代码如下:
int[,] arr = new int[3,2]; //声明一个二维数组并对其初始化
说明:以上二维数组中的每个元素都初始化为0。定义数值型的数组时,其默认值为0(这里包括整型、单精度型和双精度型),布尔型数组的默认值为false,字符型数组的默认值为'\0',字符串型数组的默认值为null。
另外,也可以在声明数组时将其初始化,并且初始化的值为用户自定义的值。
例如,声明一个int类型的二维数组,在声明时,直接将二维数组的值初始化为用户自定义的值,代码如下:
int[,] arr = new int[3,2] { { 1,2 }, { 3,4 }, { 5,6 } }; //声明一个数组,并初始化为用户自定义值
说明:数组大小必须与大括号中的元素个数相匹配,否则会产生编辑错误。
三、任务实施
- 启动Visual Studio 2010应用程序。执行“开始”→“所有程序”→“Microsoft Visual Studio 2010”→“Microsoft Visual Studio 2010”命令,打开Visual Studio 2010应用程序窗口。
- 新建项目。启动Visual Studio 2010系统创建一个控制台应用程序。
- 创建一个控制台应用程序,首先定义一个
int类型的二维数组,然后使用for循环将数组元素值读取出来。代码如下:
static void Main(string[] args)
{
int[,] id = new int[3,2] { { 1,2 }, { 3,4 }, { 5,6 } }; //定义了一个3行2列的二维数组
for (int i = 0; i < 3; i++) //遍历行数
{
for (int j = 0; j < 2; j++) //遍历列数
{
Console.Write(id[i,j]);
}
Console.WriteLine(); //换行输出
}
Console.ReadLine();
}
程序运行结果如图6-2所示:
12
34
56
图6-2 二维数组的输出
数组的输入与输出指的是对不同维数的数组进行输入和输出的操作。数组的输入和输出可以用for语句来实现,由以上程序可知二维数组的输入输出是用双层循环语句实现的。多维数组的输入输出与二维数组的输入输出相同,只是根据维数来指定循环的层数。
在 C# 中,int[,] 和 int[][] 都表示二维的整数集合,但它们在内存布局、语法、性能和使用场景上有本质区别。
一、基本定义
| 类型 | 名称 | 声明示例 | 含义 |
|---|---|---|---|
int[,] | 多维数组(矩形数组) | int[,] matrix = new int[3, 4]; | 一个严格的 3 行 × 4 列 的矩形表格,所有行长度相同。 |
int[][] | 锯齿数组(数组的数组) | int[][] jagged = new int[3][]; | 一个一维数组,其中每个元素又是一个 一维 int 数组,每个内层数组的长度可以不同。 |
二、详细对比
1. 内存布局
int[,]:单块连续内存,所有元素按行优先顺序存储。
例如new int[2,3]在内存中为[0,0][0,1][0,2][1,0][1,1][1,2]连续排布。int[][]:外层数组存储的是引用(指向内层数组的指针),内层数组各自在堆上独立分配,可能不是连续内存。
2. 声明与初始化
int[,](必须同时指定行数和列数,或直接初始化):
int[,] rect = new int[2, 3]; // 2行3列,全0
int[,] rect2 = { { 1, 2, 3 }, { 4, 5, 6 } }; // 直接初始化
int[][](先指定外层长度,再逐个为内层创建数组):
int[][] jagged = new int[2][]; // 外层有2个元素(每个是一个int[])
jagged[0] = new int[3]; // 第0行有3个元素
jagged[1] = new int[2]; // 第1行有2个元素
// 或直接初始化
int[][] jagged2 = new int[][]
{
new int[] { 1, 2, 3 },
new int[] { 4, 5 }
};
3. 访问元素
int[,]:rect[行, 列]int[][]:jagged[行][列](先取出行数组,再取列)
4. 获取维度长度
int[,]:
rect.GetLength(0)→ 行数
rect.GetLength(1)→ 列数
rect.Rank→ 维度数(2)int[][]:
jagged.Length→ 外层数组长度(行数)
jagged[0].Length→ 第0行的列数(可能每行不同)
5. 性能
int[,]:- 优点:内存连续,缓存命中率高,遍历(尤其是按行)速度更快。
- 缺点:所有行必须等长,灵活性差。
int[][]:- 优点:每行可以不等长(例如三角形矩阵),更灵活。
- 缺点:两次间接寻址(先找行数组引用,再找元素),内存不连续,可能略慢。
实际性能差异通常很小,除非极端性能场景(如数值计算),否则优先考虑语义清晰。
6. 适用场景
| 场景 | 推荐类型 | 原因 |
|---|---|---|
| 矩阵运算、图像处理、表格数据(行数列数固定) | int[,] | 内存连续,访问直观,速度快 |
| 不规则数据(如每行长度不同、稀疏结构) | int[][] | 灵活,节省内存(不用为短行预留长空间) |
| 需要与C/C++互操作(P/Invoke) | int[,] | 内存布局是连续块,容易传递 |
| 动态增加行或列(例如从文件读取不确定长度的行) | int[][] | 可以方便地替换某行为新数组 |
三、代码示例对比
// 矩形数组 int[,]
int[,] rect = new int[2, 3];
rect[0, 0] = 1;
rect[0, 1] = 2;
rect[0, 2] = 3;
rect[1, 0] = 4;
rect[1, 1] = 5;
rect[1, 2] = 6;
// 遍历矩形数组
for (int i = 0; i < rect.GetLength(0); i++)
{
for (int j = 0; j < rect.GetLength(1); j++)
Console.Write(rect[i, j] + " ");
Console.WriteLine();
}
// 输出:
// 1 2 3
// 4 5 6
// 锯齿数组 int[][]
int[][] jagged = new int[2][];
jagged[0] = new int[3] { 1, 2, 3 };
jagged[1] = new int[2] { 4, 5 };
// 遍历锯齿数组
for (int i = 0; i < jagged.Length; i++)
{
for (int j = 0; j < jagged[i].Length; j++)
Console.Write(jagged[i][j] + " ");
Console.WriteLine();
}
// 输出:
// 1 2 3
// 4 5
四、总结
| 特性 | int[,] | int[][] |
|---|---|---|
| 中文名称 | 二维数组 / 矩形数组 | 锯齿数组 / 数组的数组 |
| 内存布局 | 单块连续内存 | 外层连续,内层独立 |
| 是否要求每行等长 | 是 | 否 |
| 访问语法 | [行,列] | [行][列] |
| 获取行数 | GetLength(0) | Length |
| 获取列数 | GetLength(1) | [行].Length |
| 性能(连续访问) | 较高 | 稍低 |
| 适用场景 | 固定行列的表格、矩阵 | 不规则数据、动态行长度 |
简单记忆:
- 矩形数组
[,]—— 像 Excel 表格,必须整齐。 - 锯齿数组
[][]—— 像一排书架,每个书架上格子数可以不同。