????????指向指針的指針是一種多級間接尋址的形式,或者說是一個指針鏈。
????????指針的指針就是將指針的地址存放在另一個指針里面。
????????通常,一個指針包含一個變量的地址。當我們定義一個指向指針的指針時,第一個指針包含了第二個指針的地址,第二個指針指向包含實際值的位置。????????
???????一個指向指針的指針變量必須如下聲明,即在變量名前放置兩個星號。例如,下面聲明了一個指向 int 類型指針的指針:
int **var;
??????????當一個目標值被一個指針間接指向到另一個指針時,訪問這個值需要使用兩個星號運算符,如下面實例所示:
#include <iostream>using namespace std;int main ()
{int var;int *ptr;int **pptr;var = 3000;// 獲取 var 的地址ptr = &var;// 使用運算符 & 獲取 ptr 的地址pptr = &ptr;// 使用 pptr 獲取值cout << "var 值為 :" << var << endl;cout << "*ptr 值為:" << *ptr << endl;cout << "**pptr 值為:" << **pptr << endl;return 0;
}
當上面的代碼被編譯和執行時,它會產生下列結果:
var 值為 :3000
*ptr 值為:3000
**pptr 值為:3000
在?C++?程序中,指針可以指向基本數據類型,如整型或字符型,從而允許我們訪問這些數據。由于指針本身也是存儲在內存中的變量,它記錄著數據的內存地址,因此指針也可以指向另一個指針,即指向指針的指針。
????????雖然這個概念初聽起來有些復雜,但可以這樣理解,指針本質上是一個存儲內存地址的變量,當有一個指針變量存儲了另一個指針變量所在內存的地址時,我們就稱這個指針為“指向指針的指針”,又稱為二級指針。
為了更清晰地展示這一概念,下面是一個實際的例子:
int N = 2;
int* pN = &N; // 定義一個指針變量pN,記錄變量N所在的內存地址
int** ppN = &pN; // 定義一個指針變量ppN,記錄指針變量pN所在的內存地址
????????在這段代碼中,首先定義了一個整型變量 N,然后定義了一個整型指針指向這個變量 N。換句話說,這個指針的值就是整型變量 N 在內存中的地址。最后,指向指針的指針 ppN 登場了,我們用?int**
?作為數據類型定義了一個指針 ppN,其中保存的就是 pN 指針變量所在內存中的地址,也就是它指向這個整型指針 pN。
????????下圖展示了這三個變量之間的關系
圖 1 指向指針的指針
????????從圖 1 中可以看到,變量 N 保存在內存地址 0016FA38 這個位置,而指針變量 pN 記錄的值是 N 所在的內存位置 0016FA38,同時它自己保存在內存地址 0016FA5C 這個位置。
????????同理,作為指向 pN 的指針,ppN 這個指針變量記錄的值是 pN 所在內存地址 0016FA5C 的位置,而它自己保存在內存地址 0016FA90 這個位置。
????????簡單來講,普通指針指向的是一個具體的數據,而指針的指針指向的是一個指針數據,我們可以把指針數據也當作某個具體的數據,它也有自己的數據類型(例如 int*),也占用一定的內存(例如 0016FA5C),記錄一定的數值(例如 0016FA37)。類比普通數據,指向指針的指針的數據類型,就是在它所指向的數據的類型之后加一個“*”。
????????例如,我們要定義一個指針指向另一個?int*
?類型的指針,那么它自身的類型就是 int* 加一個“*”就成了?int**
。而這個指針的值,同樣是用“&”取得被指向的指針變量的地址賦給它,于是它就成為指向這個指針的指針。
????????在 C++ 中,可以用下面的語法格式來定義一個二級指針:
數據類型** 指針變量名
其中,數據類型表示它所指向的指針的數據類型。例如:
-
int** ppN = &pN;
????????這樣就定義了一個指向整型指針的二級指針 ppN,它指向另一個指針變量 pN,而 pN 指針變量又指向一個整型變量。
????????二級指針通常用來訪問指針數組。數組不僅可以保存基本數據類型的數據,還可以保存指針,保存指針的數組被稱為指針數組。如果要訪問一個指針數組,使用二級指針最為方便。
// 這是一個指針數組,其中保存的是各個字符串常量的首地址指針,其類型是 const char*
const char* arrMonth[] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};// 定義一個指向指針的指針
// 因為要指向的指針是 const char*類型,所以加上*后它自身的類型就是 const char**
// 這里數組的首地址 arrMonth 就是數組的第一個元素
// 也就是指向第一個字符串 “Jan” 的指針
const char** pMonth = arrMonth;// 獲取用戶輸入
int nIndex = 0;
cout << "請輸入月份對應的數字: " << endl;
cin >> nIndex;
// 對指針進行運算,使其指向相應的數組元素
// 也就是相應的字符串指針
const char* pCurMonth = *(pMonth + (nIndex - 1));
cout << "對應的月份是: " << pCurMonth << endl;
????????在以上這段代碼中,arrMonth 數組中保存的是多個字符串常量的指針,這些指針的數據類型是?const char*
。
????????為了利用指針偏移方便地訪問數組中的各個字符串,我們需要一個可以指向這些字符串元素的指針,因為字符串元素的類型是?const char*
,所以我們定義了一個?const char**
?類型的二級指針 pMonth,并將字符串數組的首地址賦值給它,使其指向字符串數組的第一個元素。然后通過對 pMonth 進行運算,讓其偏移指向數組中所對應的字符串元素。
????????指針運算后得到的仍然是指針,我們需要用“*”符號取得這個指針所指向的內容,才能得到對應的字符串指針,直接輸出就可以得到數字對應的月份字符串