數組分類速覽
| 類型 | 聲明語法 | 內存佈局 | 適用場景 |
| 一維數組 | T[] | 連續塊 | 列表、序列、緩衝區 |
| 多維數組 (矩形) | T[,], T[,,] | 單一連續塊,行優先 | 矩陣、棋盤、圖像像素 |
| 交錯數組 | T[][] | 數組的數組,每行獨立分配 | 不規則表格、稀疏矩陣、每行長度不同 |
一維數組
創建與初始化
// 1. 指定長度,默認值填充
string[] arr1 = new string[3]; // [null, null, null]
// 2. 集合初始化器 (推薦)
string[] arr2 = new string[] { "a", "b", "c" };
string[] arr3 = { "x", "y", "z" }; // 簡寫
// 3. 隱式類型 (var)
var arr4 = new[] { 1, 2, 3 }; // int[]
遍歷方式
foreach (var item in arr) { } // 唯讀遍歷
for (int i = 0; i < arr.Length; i++) { } // 需索引/修改
for (int i = arr.Length - 1; i >= 0; i--) { } // 逆序
多維數組 (Rectangular Array)
聲明與訪問
// 3x3 矩陣
int[,] matrix = new int[3, 3]
{
{ 1, 2, 3 },
{ 4, 5, 6 },
{ 7, 8, 9 }
};
// 訪問:matrix[row, col]
int center = matrix[1, 1]; // 5
// 獲取維度長度
int rows = matrix.GetLength(0); // 3
int cols = matrix.GetLength(1); // 3
int rank = matrix.Rank; // 2
遍歷模式
// 行優先 (緩存友好)
for (int r = 0; r < rows; r++)
for (int c = 0; c < cols; c++)
Console.Write(matrix[r, c] + " ");
// foreach 遍歷順序同行優先
foreach (int val in matrix) { }
交錯數組
創建 (每行長度可異)
// 先分配行數組
int[][] jagged = new int[2][];
// 再為每行分配列數組
jagged[0] = new int[] { 1, 2, 3, 4 };
jagged[1] = new int[] { 5, 6, 7, 8 };
// 或一步到位
int[][] jagged2 =
{
new int[] { 1, 2, 3 },
new int[] { 4, 5 },
new int[] { 6, 7, 8, 9 }
};
訪問與遍歷
int val = jagged[1][2]; // 第2行第3列 = 7
// 遍歷:外層行,內層列
for (int r = 0; r < jagged.Length; r++)
{
for (int c = 0; c < jagged[r].Length; c++)
Console.Write(jagged[r][c] + " ");
Console.WriteLine();
}
核心區別:內存與性能
- 多維數組:單塊內存,訪問需計算偏移
row * cols + col,CLR 有邊界檢查優化,但 GetLength、索引器調用有微小開銷。
- 交錯數組:每行獨立對象,訪問
arr[row][col] 經過兩次索引器,但 JIT 優化極好,實際往往更快;適合行長度不一、大稀疏矩陣。
- Span/Memory:.NET Core 2.1+ 推薦用
Span<T> 切片一維數組模擬多維,避免分配開銷,性能最優。
常用操作 (System.Array / LINQ)
int[] nums = { 5, 2, 9, 1, 5 };
Array.Sort(nums); // 原地排序: [1,2,5,5,9]
Array.Reverse(nums); // 反轉
int idx = Array.IndexOf(nums, 5); // 2
int[] copy = new int[nums.Length];
Array.Copy(nums, copy, nums.Length);
// LINQ (需 using System.Linq)
var distinct = nums.Distinct().ToArray();
var even = nums.Where(n => n % 2 == 0).ToArray();
var sum = nums.Sum();
數組與集合轉換
List list = new List { "a", "b" };
string[] arr = list.ToArray();
string[] arr2 = { "x", "y" };
List list2 = new List(arr2);
// 或
List list3 = arr2.ToList();
避坑指南
| 陷阱 | 正確做法 |
| 數組長度不可變 | 需動態增減用 List<T>,或 Array.Resize(ref arr, newSize) |
| 結構體數組修改副本 | arr[i].X = 1 報錯,需 var t = arr[i]; t.X = 1; arr[i] = t; 或改用類 |
| 多維數組用 [,] 而非 [][ | 別寫成 int[][] m = new int[3][3] (編譯錯誤) |
| foreach 中修改元素 | 不可修改迭代變量,需用 for 循環 |
| 大數組在堆上 (LOH) | >85KB 進入大對象堆,頻繁分配導致碎片,考慮 ArrayPool<T>.Shared 租用 |
現代高性能替代:Span<T> / Memory<T>
int[] data = new int[1000];
Span slice = data.AsSpan(100, 200); // 無分配切片
slice.Fill(42); // 高效填充
// 二維邏輯映射到一維 Span
int Width = 100, Height = 100;
Span buffer = new int[Width * Height];
int GetIndex(int x, int y) => y * Width + x;
buffer[GetIndex(10, 20)] = 123;
總結
- 固定長度、高性能、連續內存 →
T[]
- 矩陣、固定行列 →
T[,]
- 不規則行長、稀疏 →
T[][]
- 高性能切片、零拷貝、栈上分配 →
Span<T> / Memory<T>
- 動態增刪、豐富 API →
List<T>
選對數據結構是寫出高效 C# 代碼的第一步。