數組是 C 語言最基礎的聚合類型,掌握其定義、初始化、內存佈局、下標與指針等價性、函數傳遞語義,是寫出高效正確代碼的前提。本文通過豐富示例系統梳理一維、多維數組的核心知識點與常見坑點。
int a[5] = {1,2,3,4,5}; // 指定長度+初始化
int b[] = {1,2,3,4,5}; // 省略長度,編譯器推導為 5
int c[10] = {0}; // 首元素 0,其餘自動補 0
int d[12] = {[1]=2, 3, [4]=9}; // C99 指定初始化器:索引 1=2, 2=3, 4=9,其餘 0
int sum = 0; for (int i = 0; i < 5; ++i) sum += a[i]; // 累加 // 複製數組:必須逐元素賦值 int e[5]; for (int i = 0; i < 5; ++i) e[i] = a[i]; // a = e 錯誤!數組名不可作左值
int search(int key, int *arr, int len) {
for (int i = 0; i < len; ++i)
if (arr[i] == key) return i;
return -1;
}
int m[3][5]; // 3行5列
int n[][5] = {{1,2,3,4,5}, {6,7,8,9,0}}; // 行數可省,列數必須給出
int p[][3] = {1,2,3,4,5,6,7,8,9}; // 按行主序自動分行:3行3列
多維數組在內存中按行主序連續存放。m[i][j] 編譯器轉換為 *(*(m+i)+j) 或 *(m[0] + i*COL + j)。
int a[2][3] = {{1,2,3},{4,5,6}};
int (*p)[3] = a; // 數組指針:指向含3個int的數組
int *q = a[0]; // 指向首元素
printf("%d %d\n", p[1][2], q[5]); // 同為 6
void foo(int arr[]) { /* 等價於 int *arr */ }
void bar(int arr[10]) { /* 長度 10 被忽略 */ }
void baz(int m[][5]) { /* 二維:第一維省略,第二維必須給出 */ }
調用時傳遞的是首元素地址,函數內 sizeof(arr) 返回指針大小而非數組大小。
void qux(int (*arr)[5]) { /* 保留類型信息,sizeof(*arr) 正確 */ }
int a[3][5]; qux(a); // 正確
| 錯誤代碼 | 問題 | 修正 |
|---|---|---|
int n; scanf("%d",&n); int a[n]; | VLA 非標準 C++,棧溢出風險 | 用 malloc 或 std::vector |
int a[5] = {1,2,3,4,5,6}; | 初始化元素超過長度 | 刪除多餘或擴大長度 |
char *s = "abc"; s[0]='x'; | 修改字符串常量 → UB | char s[] = "abc"; |
void f(int a[][]) {} | 多維數組參數缺少列數 | void f(int a[][COL]) |
_Static_assert(sizeof(arr)/sizeof(arr[0]) == N, "");foo((int[]){1,2,3}); (C99)char data[]; 實現變長對象(詳見另一文章)。數組看似簡單,實則蘊含指針算術、內存佈局、類型系統等核心機制。深入理解其本質,能讓你在系統編程、嵌入式開發、高性能計算中游刃有餘。