# C++ Pointer 指針簡單入手 主要透過自己的理解,解析行為上的區分使用,能夠比較直觀的知道 \* 跟 &,分別在哪種情況上如何運用,先拋開細項**聲明 (Declaration)**、**定義 (Definition)**、**初始 (Initialization)**、**賦值 (Assignment)**,僅以『聲明』跟『賦值』作為行為兩大點,當然視每個人理解角度,都可以自行重新詮釋。 Reference: - [Effective C++笔记之一:声明、定义、初始化与赋值](https://blog.csdn.net/caoshangpa/article/details/79431094) ## 辨別 \* 跟 & 行為 將行為拆成『聲明』跟『賦值』這兩點作為切入點。 ```c++ // 聲明 int a,並且賦值為 10 (即宣告跟定義)。 int a = 10; ``` ### 聲明 (Declaration) \* 跟 & 在『聲明』的行為如下: - \*:位址容器 <font color=#EE82EE size=2>(指針即指向)</font>,僅存位址 <font color=#EE82EE size=2>(有幾層就需要聲明幾層 int**~N -> 指針陣列)</font>。 - \* 指針:**int\* aPtr**。 - &:引用值內容 <font color=#EE82EE size=2>(共享位址)</font>,僅引用值,即 Ref = Reference (引用)。 - & 引用:**int& aRef**。 #### 聲明 \* 作為位址容器,額外補充: 以下的 0x 為模擬,不是真實內存位址。 ```c++ int a = 10; // 0x1 存放 10 int* aPtr = &a; // 0x2 存放 0x1 int** aPtr2 = &aPtr; // 0x3 存放 0x2 (但 0x2 包含 0x1,即兩層位址) ``` | 變數 | 位址 | 內容 | 備註 | |:-:|:-:|:-:|:-| | a | 0x1 | 10 | | | aPtr (\*) | 0x2 | 0x1 | **內容**能放一層 (0x1) | | aPtr2 (\*\*) | 0x3 | 0x2 | **內容**能放兩層 (0x2, 0x1) | > 跟洋蔥一樣,<font color=#ed8a00>如果你願意一層一層,一層的剝開我的心</font> <font color=#008aed size=2>(引用歌詞 - 洋蔥)</font>。 > 這也是 C++ 看到後面頭暈的原因😨。 ### 賦值 (Assignment) \* 跟 & 在『賦值』的行為如下: - \*:取出位址的內容 <font color=#EE82EE size=2>(可連續,這裡使用"取出"代替"指向"比較好理解)</font>,即 Deref = Dereference (解引用)。 - \* 取址內容:**\*&a** -> 10 〔<font color=#00a33c>通過</font>〕 - &:取出位址 <font color=#EE82EE size=2>(不可連續,但可交互取址,\* 跟 & 相互抵銷)</font>。 - & 取址:**&a** -> **0x7ffd7aee4534** 〔<font color=#00a33c>通過</font>〕。 - \* 跟 & 交互:**&a** -> **0x7ffd7aee4534** -> **\*&a** -> 10 〔<font color=#00a33c>通過</font>〕。 - & 連續:**&&a** 〔<font color=#a3001b>報錯</font>〕。 --- ## 運行測試 ### 測試一 將以上對應的行為觀念套用在「= 等式」的左右行為中 <font color=#FF006F size=2>(左邊行為『聲明』 = 右邊行為『賦值』)</font>。 - 「= 等式」的左邊行為即『聲明』。 - 「= 等式」的右邊行為即『賦值』。  [OnlineGDB C++ Compiler](https://www.onlinegdb.com/online_c++_compiler) ```c++ #include <iostream> int main() { int a = 10; // 聲明 int a,並且賦值 10。 int* aPtr = &a; // 聲明 int* aPtr,存放 &a (取址) 位址。 int& aRef = a; // 聲明 int& aRef,引用 a 值內容 (共享 a 位址)。 std::cout << "a -> " << a << std::endl; // 印出 a 值。 std::cout << "aPtr -> " << aPtr << std::endl; // 印出 a 址 (point to a)。 std::cout << "aRef -> " << aRef << std::endl; // 印出 a 值 (ref a)。 return 0; } ```  ### 測試二 『賦值』行為即『使用』。 [OnlineGDB C++ Compiler](https://www.onlinegdb.com/online_c++_compiler) ```c++ #include <iostream> int main() { int a = 10; // 聲明 int a,並且賦值 10。 int* aPtr = &a; // 聲明 int* aPtr,存放 &a (取址) 位址。 int& aRef = a; // 聲明 int& aRef,引用 a 值內容 (共享 a 位址)。 std::cout << "&a -> " << &a << std::endl; // 使用 & 取 a 址。 std::cout << "&aPtr -> " << &aPtr << std::endl; // 使用 & 取 aPtr 址。 std::cout << "&aRef -> " << &aRef << std::endl; // 使用 & 取 a 址 (ref a)。 return 0; } ```  ### 測試三 『賦值』行為即『使用』。 [OnlineGDB C++ Compiler](https://www.onlinegdb.com/online_c++_compiler) ```c++ #include <iostream> int main() { int a = 10; // 聲明 int a,並且賦值 10。 int* aPtr = &a; // 聲明 int* aPtr,存放 &a (取址) 位址。 int& aRef = a; // 聲明 int& aRef,引用 a 值內容 (共享 a 位址)。 std::cout << "*&a -> " << *&a << std::endl; // 使用 & 取 a 址,並且使用 * 取址的內容。 std::cout << "*&aPtr -> " << *&aPtr << std::endl; // 使用 & 取 aPtr 址,並且使用 * 取址的內容 (上一層)。 std::cout << "**&aPtr -> " << **&aPtr << std::endl; // 使用 & 取 aPtr 址,並且使用 ** 取址的內容 (上上一層)。 std::cout << "*&aRef -> " << *&aRef << std::endl; // 使用 & 取 a 址 (ref a),並且使用 * 取址的內容。 return 0; } ```  --- ## 補充說明 如果要『賦值』記得必須是相同類型,且相同層級。 - 【址】對應【址】 ```c++ int* ptr; // 聲明 int** ptr2; // 聲明 int a = 10; // 值 int b = 20; // 值 ptr = new int; // 初始動態分配 // ↑ OR ↓ ptr = &a; // 址 <-> 址 // ↑ OR ↓ ptr = &b; // 址 <-> 址 // ↑ OR ↓ ptr2 = new int*[2]; // 初始動態分配 (指針陣列) // ↑ OR ↓ *ptr2 = &a // 址 <-> 址 (同層) ``` 額外針對【指針陣列】初始方式: ```c++ int** ptr2; // 聲明 // 方法一: // 直接初始指針陣列 ptr2 = new int*[2] { new int, new int }; // 方法二: // 為每個指針分配內存 (給每個指針分配一個整數的內存空間) for (int i = 0; i < 2; ++i) { ptr2[i] = new int; } ``` - 【值】對應【值】 ```c++ int* ptr = new int; // 聲明 + 初始 int a = 10; // 值 int b = 20; // 值 *ptr = a; // 值 <-> 值 // ↑ OR ↓ *ptr = b; // 值 <-> 值 // ↑ OR ↓ *ptr = 30; // 值 <-> 值 ```
×
Sign in
Email
Password
Forgot password
or
By clicking below, you agree to our
terms of service
.
Sign in via Facebook
Sign in via Twitter
Sign in via GitHub
Sign in via Dropbox
Sign in with Wallet
Wallet (
)
Connect another wallet
New to HackMD?
Sign up