指標基礎知識
Version < C++ 11
注意: 在以下所有內容中,假設存在 C++ 11 常量 nullptr
。對於早期版本,將 nullptr
替換為 NULL
,NULL
是用於扮演類似角色的常量。
建立指標變數
可以使用特定的*
語法建立指標變數,例如 int *pointer_to_int;
。
當變數是指標型別 (int *
)時,它只包含一個記憶體地址。儲存器地址是儲存基礎型別 (int
)的資料的位置。
將變數的大小與指向同一型別的指標的大小進行比較時,差異很明顯:
// Declare a struct type `big_struct` that contains
// three long long ints.
typedef struct {
long long int foo1;
long long int foo2;
long long int foo3;
} big_struct;
// Create a variable `bar` of type `big_struct`
big_struct bar;
// Create a variable `p_bar` of type `pointer to big_struct`.
// Initialize it to `nullptr` (a null pointer).
big_struct *p_bar0 = nullptr;
// Print the size of `bar`
std::cout << "sizeof(bar) = " << sizeof(bar) << std::endl;
// Print the size of `p_bar`.
std::cout << "sizeof(p_bar0) = " << sizeof(p_bar0) << std::endl;
/* Produces:
sizeof(bar) = 24
sizeof(p_bar0) = 8
*/
取另一個變數的地址
指標可以作為正常變數在彼此之間分配; 在這種情況下,它是從一個指標複製到另一個指標的記憶體地址,而不是指標指向的實際資料。
而且,它們可以取值 nullptr
,它表示空的記憶體位置。等於 nullptr
的指標包含無效的記憶體位置,因此它不引用有效資料。
你可以通過在變數前加上運算子 &
的地址來獲取給定型別變數的記憶體地址。&
返回的值是指向基礎型別的指標,該型別包含變數的記憶體地址( 只要變數不超出範圍,它就是有效資料 )。
// Copy `p_bar0` into `p_bar_1`.
big_struct *p_bar1 = p_bar0;
// Take the address of `bar` into `p_bar_2`
big_struct *p_bar2 = &bar;
// p_bar1 is now nullptr, p_bar2 is &bar.
p_bar0 = p_bar2;
// p_bar0 is now &bar.
p_bar2 = nullptr;
// p_bar0 == &bar
// p_bar1 == nullptr
// p_bar2 == nullptr
與參考文獻相反:
- 分配兩個指標不會覆蓋分配的指標所指的記憶體;
- 指標可以為 null。
- 明確要求運算子的地址。
訪問指標的內容
由於獲取地址需要 &
,因此訪問內容需要使用解除引用運算子 *
作為字首。當指標被取消引用時,它將成為基礎型別的變數(實際上是對它的引用)。然後可以讀取和修改它,如果不是 const
。
(*p_bar0).foo1 = 5;
// `p_bar0` points to `bar`. This prints 5.
std::cout << "bar.foo1 = " << bar.foo1 << std::endl;
// Assign the value pointed to by `p_bar0` to `baz`.
big_struct baz;
baz = *p_bar0;
// Now `baz` contains a copy of the data pointed to by `p_bar0`.
// Indeed, it contains a copy of `bar`.
// Prints 5 as well
std::cout << "baz.foo1 = " << baz.foo1 << std::endl;
*
和運算子 .
的組合縮寫為 ->
:
std::cout << "bar.foo1 = " << (*p_bar0).foo1 << std::endl; // Prints 5
std::cout << "bar.foo1 = " << p_bar0->foo1 << std::endl; // Prints 5
取消引用無效指標
取消引用指標時,應確保指向有效資料。取消引用無效指標(或空指標)可能導致記憶體訪問衝突,或讀取或寫入垃圾資料。
big_struct *never_do_this() {
// This is a local variable. Outside `never_do_this` it doesn't exist.
big_struct retval;
retval.foo1 = 11;
// This returns the address of `retval`.
return &retval;
// `retval` is destroyed and any code using the value returned
// by `never_do_this` has a pointer to a memory location that
// contains garbage data (or is inaccessible).
}
在這種情況下,g++
和 clang++
正確發出警告:
(Clang) warning: address of stack memory associated with local variable 'retval' returned [-Wreturn-stack-address]
(Gcc) warning: address of local variable ‘retval’ returned [-Wreturn-local-addr]
因此,當指標是函式的引數時必須小心,因為它們可以為 null:
void naive_code(big_struct *ptr_big_struct) {
// ... some code which doesn't check if `ptr_big_struct` is valid.
ptr_big_struct->foo1 = 12;
}
// Segmentation fault.
naive_code(nullptr);