指標宣告
指標是一種物件型別,它引用一個函式或另一個型別的物件,可能新增限定符。指標也可以不引用任何東西,這由特殊的空指標值指示。
目錄 |
[編輯] 語法
在指標宣告的宣告語法中,型別指定符序列指定了所指向的型別(可以是函式型別或物件型別,並且可以是不完整的),而宣告符的形式是
* 屬性指定符序列 (可選) 限定符 (可選) 宣告符 |
|||||||||
其中 宣告符 可以是命名所宣告指標的識別符號,包括另一個指標宣告符(這將指示一個指向指標的指標)
float *p, **pp; // p is a pointer to float // pp is a pointer to a pointer to float int (*fp)(int); // fp is a pointer to function with type int(int)
出現在 *
和識別符號(或其他巢狀宣告符)之間的 限定符 限定了所宣告指標的型別
int n; const int * pc = &n; // pc is a non-const pointer to a const int // *pc = 2; // Error: n cannot be changed through pc without a cast pc = NULL; // OK: pc itself can be changed int * const cp = &n; // cp is a const pointer to a non-const int *cp = 2; // OK to change n through cp // cp = NULL; // Error: cp itself cannot be changed int * const * pcp = &cp; // non-const pointer to const pointer to non-const int
屬性指定符序列(C23) 是一個可選的屬性列表,應用於所宣告的指標。
[編輯] 解釋
指標用於間接定址,這是一種普遍存在的程式設計技術;它們可以用於實現按引用傳遞語義,訪問具有動態儲存期的物件,實現“可選”型別(使用空指標值),結構體之間的聚合關係,回撥(使用函式指標),通用介面(使用 void 指標),以及更多。
[編輯] 指向物件的指標
指向物件的指標可以用應用於物件型別(可以是不完整的)表示式的取地址運算子的結果進行初始化
int n; int *np = &n; // pointer to int int *const *npp = &np; // non-const pointer to const pointer to non-const int int a[2]; int (*ap)[2] = &a; // pointer to array of int struct S { int n; } s = {1} int* sp = &s.n; // pointer to the int that is a member of s
指標可以作為解引用運算子(一元 *
)的操作數出現,該運算子返回標識所指向物件的左值
int n; int* p = &n; // pointer p is pointing to n *p = 7; // stores 7 in n printf("%d\n", *p); // lvalue-to-rvalue conversion reads the value from n
指向結構體和聯合體型別物件的指標也可以作為透過指標成員訪問運算子 ->
的左運算元。
由於陣列到指標的隱式轉換,指向陣列第一個元素的指標可以用陣列型別的表示式進行初始化
int a[2]; int *p = a; // pointer to a[0] int b[3][3]; int (*row)[3] = b; // pointer to b[0]
某些加法、減法、複合賦值、增量和減量運算子為指向陣列元素的指標定義。
比較運算子在某些情況下為指向物件的指標定義:表示相同地址的兩個指標比較相等,兩個空指標值比較相等,指向同一陣列元素的指標比較結果與這些元素的陣列索引相同,指向結構體成員的指標按這些成員的宣告順序比較。
許多實現還提供了隨機來源指標的嚴格全序,例如,如果它們在連續(“扁平”)虛擬地址空間中作為地址實現。
[編輯] 指向函式的指標
指向函式的指標可以用函式的地址進行初始化。由於函式到指標的轉換,取地址運算子是可選的
void f(int); void (*pf1)(int) = &f; void (*pf2)(int) = f; // same as &f
與函式不同,函式指標是物件,因此可以儲存在陣列中,複製,賦值,作為引數傳遞給其他函式等。
函式指標可以在函式呼叫運算子的左側使用;這會呼叫所指向的函式
#include <stdio.h> int f(int n) { printf("%d\n", n); return n * n; } int main(void) { int (*p)(int) = f; int x = p(7); }
解引用函式指標會產生所指向函式的函式指示符
int f(); int (*p)() = f; // pointer p is pointing to f (*p)(); // function f invoked through the function designator p(); // function f invoked directly through the pointer
相等比較運算子為函式指標定義(如果它們指向同一個函式,則比較相等)。
由於函式型別的相容性忽略函式引數的頂層限定符,因此引數僅在頂層限定符上有所不同的函式指標是可互換的
int f(int), fc(const int); int (*pc)(const int) = f; // OK int (*p)(int) = fc; // OK pc = p; // OK
[編輯] 指向 void 的指標
任何型別的物件指標都可以隱式轉換為void指標(可選地帶有const或volatile限定符),反之亦然
int n=1, *p=&n; void* pv = p; // int* to void* int* p2 = pv; // void* to int* printf("%d\n", *p2); // prints 1
void 指標用於傳遞未知型別的物件,這在通用介面中很常見:malloc 返回 void*,qsort 期望使用者提供的回撥函式接受兩個 const void* 引數。pthread_create 期望使用者提供的回撥函式接受並返回 void*。在所有情況下,呼叫者都有責任在使用前將指標轉換為正確的型別。
[編輯] 空指標
每種型別的指標都有一個特殊值,稱為該型別的空指標值。值為 null 的指標不指向物件或函式(解引用空指標是未定義行為),並且與所有值為null的相同型別的指標比較相等。
要將指標初始化為空或將空值賦給現有指標,可以使用空指標常量(NULL,或任何其他值為零的整數常量)。靜態初始化也將指標初始化為其空值。
空指標可以指示物件的缺失,也可以用於指示其他型別的錯誤條件。通常,接收指標引數的函式幾乎總是需要檢查值是否為 null 並以不同方式處理該情況(例如,當傳遞空指標時,free 不做任何事情)。
[編輯] 注意
儘管任何物件指標都可以強制轉換為不同型別的物件指標,但解引用指向與物件宣告型別不同的型別的指標幾乎總是未定義行為。有關詳細資訊,請參閱嚴格別名。
可以向透過指標訪問物件的函式指示這些指標不發生別名。有關詳細資訊,請參閱restrict。 |
(C99 起) |
在大多數上下文中使用的陣列型別的左值表示式會經歷到陣列第一個元素的指標的隱式轉換。有關詳細資訊,請參閱陣列。
char *str = "abc"; // "abc" is a char[4] array, str is a pointer to 'a'
指向 char 的指標通常用於表示字串。要表示有效的位元組字串,指標必須指向 char 陣列中的一個 char 元素,並且在大於或等於指標引用的元素索引的某個索引處必須有一個值為零的 char。
[編輯] 參考文獻
- C23 標準 (ISO/IEC 9899:2024)
- 6.7.6.1 指標宣告符 (p: TBD)
- C17 標準 (ISO/IEC 9899:2018)
- 6.7.6.1 指標宣告符 (p: 93-94)
- C11 標準 (ISO/IEC 9899:2011)
- 6.7.6.1 指標宣告符 (p: 130)
- C99 標準 (ISO/IEC 9899:1999)
- 6.7.5.1 指標宣告符 (p: 115-116)
- C89/C90 標準 (ISO/IEC 9899:1990)
- 3.5.4.1 指標宣告符
[編輯] 另請參閱
C++ 文件,關於 指標宣告
|