根本原因在于多维数组底层是“数组的数组”嵌套结构,内存分配必须分层进行:先为外层数组(行指针)分配空间,再逐行为内层数组(列)单独分配,否则访问未初始化行会抛出nullreferenceexception。

多维数组初始化需要分别分配空间,根本原因在于它的底层结构不是“一块连续的二维格子”,而是“数组的数组”。这种嵌套结构决定了内存分配必须分层进行,不能一步到位。
第一维是容器,必须先建好“架子”
以二维数组为例,int[][] arr 这个声明只创建了一个引用变量,什么空间都没占。真正开始分配,得先用 new int[3][] 给外层数组(即“行指针数组”)分配 3 个元素的空间——每个元素将来要存一个一维数组的地址。这一步不完成,连下标 arr[0] 都无法安全访问,否则就是 null 引用。
第二维可独立、可不等长,必须单独初始化
外层数组建好后,每个位置默认是 null,不代表自动有了列。你得手动为每一行分配具体的一维数组:
- arr[0] = new int[4]; → 第 0 行有 4 列
- arr[1] = new int[2]; → 第 1 行只有 2 列(形成“锯齿数组”)
- arr[2] = new int[5]; → 第 2 行有 5 列
这种灵活性意味着第二维无法统一推断大小,必须显式指定并单独分配。
内存布局决定不能跳过中间层
即使使用矩形二维数组语法(如 int[,] matrix = new int[2,3];),C# 或 Java 的托管运行时仍需先构建外层数组结构,再填充所有元素。值类型数组会一次性分配 6 个 int 的连续空间;而引用类型数组(如 string[][])则先分配 2 个 string[] 引用的空间,再分别为每个 string[] 分配其内部元素空间——两层分配逻辑不可合并。
不分别分配会出什么问题?
常见错误包括:
- 只声明 int[][] a; 就直接写 a[0][0] = 1; → 抛出 NullReferenceException
- 误以为 new int[2][] 已经给每行分配了列 → 实际上所有行仍是 null,未分配任何 int 元素空间
- 混淆 int[2][3](Java 锯齿)和 int[2,3](C# 矩形)的分配语义,导致预期与实际不符











