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

C語言指針進階:從基礎語法到多維數組、指針數組、多重指針的完整圖解

     編輯:C 語言入門

指針核心三問

  1. 怎麼定義:`類型 *指針名;` —— 基類型決定指向對象大小與解引用類型。
  2. 怎麼賦值:`p = &變量;` / `p = 數組名;` / `p = malloc(...);` —— 取地址、首地址、動態分配。
  3. 怎麼取值:`*p` 解引用訪問對象;`p[i]` 等價 `*(p+i)`。

指針與數組的深度綁定

一維數組

int a[5] = {1,2,3,4,5};
int *p = a;        // p 指向 a[0]
p[2] == *(p+2) == a[2] == *(a+2) // 完全等價
// 關鍵:a 是常量指針,不可修改;p 是變量,可 p++ 遍歷

指針算術:`p + n` = 地址 + n × sizeof(*p)。`p++` 移動到下一個元素。

二維數組指針圖解

int a[3][4] = {
    {1,2,3,4},
    {5,6,7,8},
    {9,10,11,12}
};

// 關鍵等價關係
a         == &a[0]           // 首行地址 (int (*)[4])
a[0]      == *(a+0)          // 第 0 行首元素地址 (int *)
a[1]      == *(a+1)          // 第 1 行首元素地址
&a[0][0]  == *a              // 第 0 行第 0 列元素地址
a[1][2]   == *(*(a+1)+2)     // 第 1 行第 2 列元素值

// 遍歷二維數組指釖法
int (*prow)[4] = a;          // 指向「含 4 個 int 的數組」的指針
for (int i = 0; i < 3; ++i) {
    for (int j = 0; j < 4; ++j)
        printf("%d ", (*prow)[j]); // 或 prow[i][j]
    ++prow;
}

指針數組 vs 二維數組

特性二維數組 int a[3][4]指針數組 int *p[3]
內存佈局連續 3×4 個 int3 個離散指針,各指向獨立 1D 數組
行長度固定 4每行可異(鋸齒數組)
分配方式一次性棧/靜態/堆分配指針數組 + 逐行 malloc
訪問語法`a[i][j]``p[i][j]` 相同語法,語義不同

多重指針(指針的指針)

int a = 10;
int *p = &a;      // 一級
int **pp = &p;    // 二級
int ***ppp = &pp; // 三級

// 解引用層級對應
***ppp = 20; // 修改 a
**pp  = 30;  // 修改 a
*p    = 40;  // 修改 a

// 典型用途:函數修改指針本身(如鏈表頭插、動態分配輸出參數)
void alloc_int(int **out) {
    *out = malloc(sizeof(int));
    **out = 42;
}
int *p; alloc_int(&p); // p 指向新分配的 42

字符串與指針

char *s = "Hello";     // s 指向唯讀區 "Hello\0"
char arr[] = "Hello";  // arr 複製到棧,可修改
s[0] = 'h'; // 崩潰!
arr[0] = 'h'; // OK

// 字符串處理函數本質:接收 char*,按 \0 遍歷
puts(s);     // 等價 fputs(s, stdout)
printf("%s", s);

函數指釖


// 定義:返回 int,兩 int 參數的函數指針類型
int (*pf)(int, int);

// 別名
typedef int (*BinaryOp)(int, int);

int add(int a, int b) { return a+b; }
int sub(int a, int b) { return a-b; }

BinaryOp ops[] = {add, sub}; // 指針數組實現策略模式
printf("%d\n", ops[0](3,4)); // 7

void* 通用指針與類型擦除

  • `void*` 可隱式轉換自/向任何對象指針(不含函數指針)。
  • 泛型容器、回調上下文、memcpy/qsort 參數均用 `void*`。
  • 使用時必須強轉回具體類型,編譯器不檢查。

常見錯誤與最佳實踐

錯誤代碼問題修正
`int *p; *p = 10;`野指針解引用`int *p = malloc(...);` 或 `int a; p=&a;`
`free(p); p[0]=1;`釋放後使用`free(p); p = NULL;`
`char *s = "abc"; s[0]='x';`修改字符串常量`char s[] = "abc";`
`scanf("%d", p);`傳指針值而非地址`scanf("%d", &x);` 或 `scanf("%d", p);` (p已是地址)
`int a[10]; a = p;`數組名不可修改`int *p = a;` 只能指針指向數組

總結

指針是 C 語言靈魂:地址、類型、解引用、算術 四要素貫穿數組、字符串、結構體、函數、動態內存。精通指針等價於精通 C 內存模型。建議動手繪圖驗證每個 `*`、`&`、`[]`、`->` 的內存動作,構建心智模型:指針 = 地址 + 類型視角。

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