首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> 關於C語言

C語言二維數組與指針深度解析:從記憶體佈局到實戰陷阱

     編輯:關於C語言

前言:數組名與指針的「似是而非」

C 語言中「數組名可看作指向首元素的指針」是初學者最易混淆的概念之一。關鍵在於:數組名不是指針,它沒有儲存地址的記憶體單元,無法賦值、無法修改。它只是編譯器在特定語境下(如傳參、取值)自動轉換為「指向首元素的常量指針」。

一維數組:char str[] vs char *str

char str1[] = "abc";  // 栈上分配 4 字節:'a','b','c','\0',str1 為首元素地址(常量)
char *str2 = "abc";   // str2 指向唯讀區的 "abc",修改 str2[0] 會觸發段錯誤

《K&R》明確規定:僅在函數形參宣告時,int a[] 與 int *a 等價;其他場合截然不同。

二維數組本質:「數組的數組」

C 標準無「二維數組」一說,int a[3][4] 實為「含 3 個元素的一維數組,每個元素是含 4 個 int 的數組」。記憶體按行優先連續佈局。

兩種宣告的根本差異

char *color[]   = {"red", "green", "blue"};  // 指針數組:3 個 char*,分離存儲
char colors[][6] = {"red", "green", "blue"}; // 二維數組:連續 3×6 字節
  • color:類型 char **,指向指針陣列首元素。
  • colors:類型 char (*)[6],指向含 6 字元數組的指針(行指針)。

指針運算實戰解碼

表達式類型含義輸出
colorchar **指針陣列首地址地址值
*colorchar *第一行字串 "red""red"
**colorchar'r''r'
(*color)[1]char第一行第 2 字元 'e''e'
*color[1]char第二行首字元 'g''g'
colorschar (*)[6]第一行地址地址值
*colorschar *退化為第一行首元素地址"red"
**(colors+1)char第二行首字元 'g''g'

關鍵規則:[] 優先級高於 *

  • *color[1] ≡ *(color[1]):先取 color[1](第二行指針),再解引用 → 'g'
  • (*color)[1]:先解引用 color 得第一行數組,再取下標 1 → 'e'

函數傳參:類型匹配的鐵律

void foo(char *p[]);        // 接受指針數組
void bar(char (*p)[6]);     // 接受行指針(列數固定)
void baz(char **p);         // 接受指針數組(退化後同 foo)

char *c[] = {...};
char d[][6] = {...};

foo(c);  // ✓
foo(d);  // ✗ 類型不匹配:char (*)[6] 無法隱式轉 char **
bar(c);  // ✗
bar(d);  // ✓

結論:二維數組退化為「行指針」,指針數組退化為「指針的指針」,兩者絕不相容。

動態分配二維數組的正確姿勢

// 方法 1:連續記憶體(模擬靜態二維數組)
int (*p)[4] = malloc(3 * sizeof *p);  // p 指向 3 行 4 列
p[1][2] = 42;                         // 正常下標訪問

// 方法 2:指針數組(行長度可變)
int **q = malloc(3 * sizeof *q);
for (int i=0; i<3; ++i) q[i] = malloc(4 * sizeof **q);
// 釋放時需逐行 free

常見坑點總結

  1. sizeof 陷阱:sizeof(arr) 給出整個數組大小;sizeof(ptr) 只給指針大小(4/8 字節)。
  2. 字串常量唯讀:char *s = "abc"; s[0]='x'; → 未定義行為(通常崩潰)。
  3. 參數退化:void f(int a[3][4]) 實為 void f(int (*a)[4]),第一維資訊丟失,需額外傳遞行數。

結語

掌握「數組即數組、指針即指針、退化只在特定語境」這一核心,配合從右向左讀取宣告(如 int (*p)[4] 讀作「p 是指向含 4 個 int 數組的指針」),即可輕鬆駕馭 C 語言最靈活也最危險的記憶體模型。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved