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

C 語言雙重指針(指針的指針)深度解析:`**` 含義、用法與內存圖解

     編輯:C 語言問答

核心概念:什麼是 `int **pp`?

int **pp 聲明一個指向「指向 int 的指針」的指針,俗稱二級指針或指針的指針。它佔用一個指針大小的內存(32 位系統 4 字節,64 位系統 8 字節),存儲的是一個一級指針變量的地址。

內存佈局圖解

int val = 100;           // 0x1000: 值 100
int *p = &val;           // 0x2000: 存儲 0x1000 (val 的地址)
int **pp = &p;           // 0x3000: 存儲 0x2000 (p 的地址)

// 內存視圖
地址      內容          說明
0x1000    100           int val
0x2000    0x1000        int *p  (指向 val)
0x3000    0x2000        int **pp (指向 p)

解引用層級

表達式類型值等價寫法
ppint **0x2000 (p 的地址)&p
*ppint *0x1000 (val 的地址)p
**ppint100 (val 的值)*p, val

三大核心應用場景

1. 函數修改指針本身(傳遞指針的地址)

void allocate(int **ptr, size_t n) {
    *ptr = malloc(n * sizeof(int));  // 修改實參指針指向的內存
}

int *arr = NULL;
allocate(&arr, 10);  // 傳遞一級指針的地址
// 此處 arr 已指向新分配的內存

關鍵:若函數參數為 int *ptr,函數內修改 ptr 只影響副本;用 int **ptr 可修改調用者的指針變量。

2. 動態二維數組(指針數組)

int **matrix = malloc(rows * sizeof(int *));
for (size_t i = 0; i < rows; ++i) {
    matrix[i] = malloc(cols * sizeof(int));
}
// 訪問:matrix[row][col] 等價於 *(*(matrix + row) + col)

// 釋放
for (size_t i = 0; i < rows; ++i) free(matrix[i]);
free(matrix);

這裡 matrix 是 int **,指向「行指針」數組,每個行指針再指向該行的數據。

3. 命令行參數 / 環境變量 / 字符串數組

int main(int argc, char *argv[]) {  // argv 實際類型 char **
    for (int i = 0; i < argc; ++i) {
        printf("argv[%d] = %s\n", i, argv[i]);
    }
    // 環境變量同理:char **environ
}

進階:三級指針與更高維度

int ***ppp = &pp;  // 指向二級指針的指針
// 解引用:***ppp == **pp == *p == val

實際工程中**極少超過三級**,過度間接會嚴重降低可讀性與性能(多次間接訪問、緩存未命中)。

常見錯誤與避坑

錯誤代碼問題修正
int **pp = &val;類型不匹配:&val 是 int *,不能賦給 int **int *p = &val; int **pp = &p;
**pp = 200; // pp 未初始化野指針解引用,導致段錯誤先初始化 pp = &p 或分配內存
free(pp); // pp 指向棧上變量釋放非堆內存,未定義行為僅釋放 malloc/calloc/realloc 返回的地址
int **pp = malloc(sizeof(int *)); *pp = malloc(sizeof(int));邏輯正確,但易忘記雙重釋放封裝 alloc_2d/free_2d 函數統一管理

調試技巧:GDB 觀察多級指針

(gdb) p pp
$1 = (int **) 0x3000
(gdb) p *pp
$2 = (int *) 0x1000
(gdb) p **pp
$3 = 100
(gdb) p /x pp
$4 = 0x3000
(gdb) x/3xg 0x3000   // 查看連續 3 個指針大小的內存
0x3000: 0x2000
0x2000: 0x1000
0x1000: 0x00000064

總結

  • ** 表示兩次間接訪問,本質是「指向指針的指針」。
  • 核心價值:**允許函數修改調用者的指針變量**,構建動態多維數組、管理字符串數組、實現多態數據結構。
  • 掌握關鍵:**畫內存圖、寫最小驗證程序、用調試器單步觀察地址變化**。
  • 工程原則:**二級足矣,三級慎用,封裝分配釋放,文檔註明所有權轉移**。

徹底理解雙重指針,是邁向 C 語言高手、閱讀系統級源碼(內核、數據庫、虛擬機)的必經之路。

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