【C++ 筆記】指標(Pointer)(上) - part 10
很感謝你點進來這篇文章。
你好,我並不是什麼 C++、程式語言的專家,所以本文若有些錯誤麻煩請各位鞭大力一點,我極需各位的指正及指導!!本系列文章的性質主要以詼諧的口吻,一派輕鬆的態度自學程式語言,如果你喜歡,麻煩留言說聲文章讚讚吧!
指標(Pointer)
在講指標之前,我們都知道變數具有「值(value)」、「資料型態(Data Type)」、「記憶體位址(Memory Address)」三種特性。
我們要存取變數的記憶體位址,需要使用「&」符號加在變數名前面獲取,如下:
透過以下範例,可以知道變數的記憶體位址如何獲取:
1 2 3 4 5 6 7 8
| #include <iostream> using namespace std;
int main(){ int a = 0; cout << &a; return 0; }
|
輸出結果:
:::success
問題來了,指標是啥呢?
:::
指標(Pointer),又稱為指針,是一個變數,可以用於儲存特定記憶體位址。
所以指標就是專門存記憶體位址的變數,存誰的?當然是其他變數的阿!
語法:
註1:指標的資料型態無論如何都一樣,其記憶體位址都表示成十六進位。但不同資料型態的指標,差異是指標所指向的變數或常數的資料型態不同。
註2:提取(Dereference)運算子 *,用來提取指標儲存位址處的物件。
以下是一個範例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| #include <iostream> using namespace std;
int main() { int number = 10; int* ptr = &number;
cout << "number 的值: " << number << endl; cout << "number 的記憶體位置: " << &number << endl; cout << "ptr 的值 (儲存的記憶體位置): " << ptr << endl; cout << "ptr 指向的值 (*ptr): " << *ptr << endl;
*ptr = 20; cout << "用指標修改後的 number 值: " << number << endl;
return 0; }
|
輸出結果:
1 2 3 4 5
| number 的值: 10 number 的記憶體位置: 0x61fe14 ptr 的值 (儲存的記憶體位置): 0x61fe14 ptr 指向的值 (*ptr): 10 用指標修改後的 number 值: 20
|
Null 指標(Null Pointer)
變數宣告時,若沒精確的地址可以指定,替指標變數賦予一個 NULL 值是良好的習慣。其名為空指標。
NULL 指標是定義在標準函式庫中的值為零的常數。
如下範例:
1 2 3 4 5 6 7 8 9 10 11 12
| #include <iostream>
using namespace std;
int main () { int *ptr = NULL;
cout << "ptr 的值是 " << ptr ; return 0; }
|
輸出結果:
來源:https://www.runoob.com/cplusplus/cpp-null-pointers.html
C++ NULL 指標應用
- 初始化(Initialization):將指標初始化為空值(nullptr)是一個良好的習慣,因為這可以避免未定義行為,並明確表示指標尚未指向有效的記憶體位置。
- 預設值(Default Values):當指標尚未分配有效的記憶體地址時,空指標可作為指標的預設值或初始值。
- 錯誤處理(Error Handling):空指標在錯誤條件下或用於表示資料缺失時非常有用,有助於更好地處理例外情況。
- 資源釋放(Resource Release):在釋放資源(例如類別的解構函數)或刪除後將指標設為空值(nullptr),可避免意外使用或存取已釋放的記憶體。
- 哨兵值(Sentinel Values):空指標可以用來表示資料結構或清單的結尾。例如,在鏈結串列中,最後一個節點的「下一個節點」欄位通常是一個空指標。
C++ NULL 指標缺點
- 提取(dereference)空指標會導致未定義行為(undefined behavior),可能引發執行時錯誤,例如記憶體區段錯誤(segmentation fault)。
- 在提取空指標之前,需要明確檢查是否為空指標,才能避免未定義行為。
Source:https://www.geeksforgeeks.org/null-pointer-in-cpp/
至於這點,可以透過條件判斷的方式避免此類型錯誤:
以下是菜鳥教程的解釋:
在大多數的作業系統上,程式不允許存取位址為 0 的記憶體,因為該記憶體是作業系統保留的。然而,記憶體位址 0 有特別重要的意義,它表明該指標不指向一個可存取的記憶體位址。但按照慣例,如果指標包含空值(零值),則假定它不指向任何東西。
因此,如果所有未使用的指標都被賦予空值,同時避免使用空指標,就可以防止誤用一個未初始化的指標。很多時候,未初始化的變數存有一些垃圾值,導致程式難以調試。
指標的算術運算(Pointer Arithmetic)
指標是一個用數值表示的位址。因此,您可以對指標執行算術運算。指標可以進行四種算術運算:++、—、+、-。
遞增指標範例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
| #include <iostream> using namespace std;
int main() { int arr[] = {10, 20, 30, 40, 50}; int size = sizeof(arr) / sizeof(arr[0]);
int* ptr = arr;
cout << "指標逐一存取陣列元素:" << endl;
for (int i = 0; i < size; ++i) { cout << "元素 " << i << ": " << *ptr << endl; ++ptr; }
ptr = arr;
cout << "\n指標修改陣列元素的值:" << endl;
for (int i = 0; i < size; ++i) { *ptr += 5; cout << "元素 " << i << " 新值: " << *ptr << endl; ++ptr; }
return 0; }
|
輸出結果:
1 2 3 4 5 6 7 8 9 10 11 12 13
| 指標逐一存取陣列元素: 元素 0: 10 元素 1: 20 元素 2: 30 元素 3: 40 元素 4: 50
指標修改陣列元素的值: 元素 0 新值: 15 元素 1 新值: 25 元素 2 新值: 35 元素 3 新值: 45 元素 4 新值: 55
|
遞增、遞減指標範例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37
| #include <iostream> using namespace std;
int main() { int numbers[] = {10, 20, 30, 40, 50}; int size = sizeof(numbers) / sizeof(numbers[0]);
int* ptr = numbers;
cout << "原始陣列:" << endl; for (int i = 0; i < size; ++i) { cout << numbers[i] << " "; } cout << endl;
cout << "指標遞增存取陣列內容:" << endl; for (int i = 0; i < size; ++i) { cout << *ptr << " "; ++ptr; } cout << endl;
ptr = numbers + size - 1;
cout << "指標遞減存取陣列內容:" << endl; for (int i = 0; i < size; ++i) { cout << *ptr << " "; --ptr; } cout << endl;
return 0; }
|
輸出結果:
1 2 3 4 5 6
| 原始陣列: 10 20 30 40 50 指標遞增存取陣列內容: 10 20 30 40 50 指標遞減存取陣列內容: 50 40 30 20 10
|
指標比較(Comparison of Pointer)
- 相等比較:用運算子「==」、「!=」
- 關係比較:用運算子「<」、「>」、「<=」、「>=」
以下是有關相等與不相等的比較範例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43
| #include <iostream> using namespace std;
int main() { int a = 10, b = 20, c = 10;
int* ptr1 = &a; int* ptr2 = &b; int* ptr3 = &c;
cout << "地址:\n"; cout << "a 的地址: " << &a << endl; cout << "b 的地址: " << &b << endl; cout << "c 的地址: " << &c << endl;
cout << "\n指標比較:\n"; if (ptr1 == ptr2) { cout << "ptr1 和 ptr2 指向相同的地址\n"; } else { cout << "ptr1 和 ptr2 指向不同的地址\n"; }
if (ptr1 == ptr3) { cout << "ptr1 和 ptr3 指向相同的地址\n"; } else { cout << "ptr1 和 ptr3 指向不同的地址\n"; }
ptr3 = &a;
cout << "\n修改 ptr3 後的比較:\n"; if (ptr1 == ptr3) { cout << "ptr1 和 ptr3 現在指向相同的地址\n"; } else { cout << "ptr1 和 ptr3 指向不同的地址\n"; }
return 0; }
|
輸出結果:
1 2 3 4 5 6 7 8 9 10 11
| 地址: a 的地址: 0x7ffee1dba88c b 的地址: 0x7ffee1dba88d c 的地址: 0x7ffee1dba88e
指標比較: ptr1 和 ptr2 指向不同的地址 ptr1 和 ptr3 指向不同的地址
修改 ptr3 後的比較: ptr1 和 ptr3 現在指向相同的地址
|
以下是有關大小比較的範例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45
| #include <iostream> using namespace std;
int main() { int arr[5] = {10, 20, 30, 40, 50};
int* ptr1 = &arr[1]; int* ptr2 = &arr[3];
cout << "指標資訊:\n"; cout << "ptr1 指向的地址: " << ptr1 << ", 值: " << *ptr1 << endl; cout << "ptr2 指向的地址: " << ptr2 << ", 值: " << *ptr2 << endl;
cout << "\n指標比較:\n"; if (ptr1 < ptr2) { cout << "ptr1 指向的地址小於 ptr2 指向的地址\n"; } else if (ptr1 > ptr2) { cout << "ptr1 指向的地址大於 ptr2 指向的地址\n"; } else { cout << "ptr1 和 ptr2 指向相同的地址\n"; }
cout << "\n更多比較:\n"; if (ptr1 <= ptr2) { cout << "ptr1 的地址小於或等於 ptr2 的地址\n"; } if (ptr2 >= ptr1) { cout << "ptr2 的地址大於或等於 ptr1 的地址\n"; }
ptr1 = &arr[3]; cout << "\n修改 ptr1 後的比較:\n"; if (ptr1 == ptr2) { cout << "現在 ptr1 和 ptr2 指向相同的地址\n"; } else { cout << "現在 ptr1 和 ptr2 指向不同的地址\n"; }
return 0; }
|
輸出結果:
1 2 3 4 5 6 7 8 9 10 11 12 13
| 指標資訊: ptr1 指向的地址: 0x7ffee6b93010, 值: 20 ptr2 指向的地址: 0x7ffee6b93018, 值: 40
指標比較: ptr1 指向的地址小於 ptr2 指向的地址
更多比較: ptr1 的地址小於或等於 ptr2 的地址 ptr2 的地址大於或等於 ptr1 的地址
修改 ptr1 後的比較: 現在 ptr1 和 ptr2 指向相同的地址
|
指標仍有許多相關的應用,本次筆記先至此結束,避免篇幅過長。
總結
本文介紹了 C++ 中的指標(Pointer),包括指標的基本概念、使用方法及相關運算,並探討空指標(Null Pointer)及其應用。
指標的基本概念
- 指標(Pointer):指標是一種變數,用於儲存其他變數的記憶體位址。其語法為
type *ptr;。 - 記憶體位址獲取:使用 & 符號來獲取變數的記憶體位址。
- 提取運算子(Dereference):* 用於提取指標所指向的值。
空指標(Null Pointer)
- 定義:其值為 NULL,表示不指向任何有效的記憶體位址。
- 應用:
- 初始化:將指標初始化為空值來避免未定義行為。
- 錯誤處理:用於表示資料缺失或錯誤情況。
- 資源釋放:在釋放資源後將指標設為空值以避免意外使用。
指標算術運算
指標可以進行算術運算,如遞增(++)、遞減(—)、加法和減法,可以方便的遍歷陣列元素。
指標比較
指標可以進行相等比較(==, !=)和關係比較(如 <, >)。
參考資料
C++ 指针的算术运算 | 菜鸟教程
C++ Pointer Arithmetic - GeeksforGeeks
指標與位址
C++ Pointers - GeeksforGeeks
NULL Pointer in C++ - GeeksforGeeks
C++ 指针 | 菜鸟教程
C++ Null 指针 | 菜鸟教程