Skip to main content

任务二 多维数组

一、多维数组是什么?

  • 多维数组,即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 } };  //声明一个数组,并初始化为用户自定义值

说明:数组大小必须与大括号中的元素个数相匹配,否则会产生编辑错误。

三、任务实施

  1. 启动Visual Studio 2010应用程序。执行“开始”→“所有程序”→“Microsoft Visual Studio 2010”→“Microsoft Visual Studio 2010”命令,打开Visual Studio 2010应用程序窗口。
  2. 新建项目。启动Visual Studio 2010系统创建一个控制台应用程序。
  3. 创建一个控制台应用程序,首先定义一个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 表格,必须整齐。
  • 锯齿数组 [][] —— 像一排书架,每个书架上格子数可以不同。