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)
| 表達式 | 類型 | 值 | 等價寫法 |
|---|---|---|---|
pp | int ** | 0x2000 (p 的地址) | &p |
*pp | int * | 0x1000 (val 的地址) | p |
**pp | int | 100 (val 的值) | *p, val |
void allocate(int **ptr, size_t n) {
*ptr = malloc(n * sizeof(int)); // 修改實參指針指向的內存
}
int *arr = NULL;
allocate(&arr, 10); // 傳遞一級指針的地址
// 此處 arr 已指向新分配的內存
關鍵:若函數參數為 int *ptr,函數內修改 ptr 只影響副本;用 int **ptr 可修改調用者的指針變量。
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 **,指向「行指針」數組,每個行指針再指向該行的數據。
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) 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 語言高手、閱讀系統級源碼(內核、數據庫、虛擬機)的必經之路。