成員訪問運算子
成員訪問運算子允許訪問其運算元的成員。
運算子 | 運算子名稱 | 示例 | 描述 |
---|---|---|---|
[] | 陣列下標 | a[b] | 訪問陣列 a 的第 b 個元素 |
* | 指標解引用 | *a | 解引用指標 a 以訪問它所指向的物件或函式 |
& | 取地址 | &a | 建立一個指向物件或函式 a 的指標 |
. | 成員訪問 | a.b | 訪問 struct 或 union a 的成員 b |
-> | 透過指標訪問成員 | a->b | 訪問指標 a 所指向的 struct 或 union 的成員 b |
目錄 |
[編輯] 下標
陣列下標表達式的形式為
pointer-expression [ integer-expression ] |
(1) | ||||||||
integer-expression [ pointer-expression ] |
(2) | ||||||||
其中
pointer-expression | - | 一個指向完整物件的指標型別的表示式 |
integer-expression | - | 一個整數型別的表示式 |
下標運算子表示式是一個左值表示式,其型別為 pointer-expression 所指向的物件的型別。
根據定義,下標運算子 E1[E2] 與 *((E1)+(E2)) 完全相同。如果 pointer-expression 是一個數組表示式,它會進行左值到右值轉換,併成為指向陣列第一個元素的指標。
由於指標與整數相加的定義,結果是索引等於 integer-expression 結果的陣列元素(或者,如果 pointer-expression 指向某個陣列的第 i 個元素,則結果的索引是 i 加上 integer-expression 的結果)。
注意:有關多維陣列的詳細資訊,請參閱陣列。
#include <stdio.h> int main(void) { int a[3] = {1,2,3}; printf("%d %d\n", a[2], // n == 3 2[a]); // same, n == 3 a[2] = 7; // subscripts are lvalues int n[2][3] = {{1,2,3},{4,5,6}}; int (*p)[3] = &n[1]; // elements of n are arrays printf("%d %d %d\n", (*p)[0], p[0][1], p[0][2]); // access n[1][] via p int x = n[1][2]; // applying [] again to the array n[1] printf("%d\n", x); printf("%c %c\n", "abc"[2], 2["abc"]); // string literals are arrays too }
輸出
3 3 4 5 6 6 c c
[編輯] 解引用
解引用或間接表示式的形式為
* pointer-expression |
|||||||||
其中
pointer-expression | - | 任何指標型別的表示式 |
如果 pointer-expression 是函式指標,則解引用運算子的結果是該函式的函式指示符。
如果 pointer-expression 是物件指標,則結果是指定所指向物件的左值表示式。
解引用空指標、指向生命週期之外物件的指標(懸空指標)、未對齊的指標或具有不確定值的指標是未定義行為,除非解引用運算子透過對其結果應用取地址運算子而無效,例如 &*E。
輸出
*p = 1 *p = 7
[編輯] 取地址
取地址表示式的形式為
& function |
(1) | ||||||||
& lvalue-expression |
(2) | ||||||||
& * expression |
(3) | ||||||||
& expression [ expression ] |
(4) | ||||||||
&
和 *
相互抵消,兩者均不求值&
和 []
中隱含的 *
相互抵消,只計算 []
中隱含的加法。其中
lvalue-expression | - | 任何型別的左值表示式,但不能是位欄位,也不能具有register儲存類 |
取地址運算子生成其運算元的非左值地址,適合用於初始化指向運算元型別的指標。如果運算元是函式指示符 (1),則結果是指向函式的指標。如果運算元是物件 (2),則結果是指向物件的指標。
如果運算元是解引用運算子,則不執行任何操作(因此對空指標應用 &* 是可以的),除了結果不是左值。
如果運算元是陣列索引表示式,則除了陣列到指標的轉換和加法之外,不執行任何操作,因此 &a[N] 對於大小為 N 的陣列是有效的(獲取指向末尾之外一個位置的指標是允許的,但解引用它是不允許的,不過在本表示式中解引用會相互抵消)。
int f(char c) { return c;} int main(void) { int n = 1; int *p = &n; // address of object n int (*fp)(char) = &f; // address of function f int a[3] = {1,2,3}; int *beg=a, *end=&a[3]; // same as end = a+3 }
[編輯] 成員訪問
成員訪問表示式的形式為
expression . member-name |
|||||||||
其中
表示式 | - | struct 或 union 型別的表示式 |
member-name | - | 一個識別符號,表示由 expression 指定的結構體或聯合體的成員 |
成員訪問表示式指定其左運算元所指定的結構體或聯合體的命名成員。它具有與其左運算元相同的值類別。
如果左運算元具有 const 或 volatile 限定符,則結果也具有相應的限定符。如果左運算元是 atomic,則行為未定義。
注意:除了命名結構體或聯合體型別的物件的識別符號之外,以下表達式也可能具有結構體或聯合體型別:賦值、函式呼叫、逗號運算子、條件運算子和複合字面量。
#include <stdio.h> struct s {int x;}; struct s f(void) { return (struct s){1}; } int main(void) { struct s s; s.x = 1; // ok, changes the member of s int n = f().x; // f() is an expression of type struct s // f().x = 1; // Error: this member access expression is not an lvalue const struct s sc; // sc.x = 3; // Error: sc.x is const, can't be assigned union { int x; double d; } u = {1}; u.d = 0.1; // changes the active member of the union }
[編輯] 透過指標訪問成員
成員訪問表示式的形式為
expression -> member-name |
|||||||||
其中
表示式 | - | 指向 struct 或 union 的 指標型別的表示式 |
member-name | - | 一個識別符號,表示由 expression 指向的結構體或聯合體的成員 |
透過指標訪問成員表示式指定其左運算元所指向的結構體或聯合體型別的命名成員。其值類別始終是左值。
如果左運算元所指向的型別具有 const 或 volatile 限定符,則結果也具有相應的限定符。如果左運算元所指向的型別是 atomic,則行為未定義。
#include <stdio.h> struct s {int x;}; int main(void) { struct s s={1}, *p = &s; p->x = 7; // changes the value of s.x through the pointer printf("%d\n", p->x); // prints 7 }
[編輯] 缺陷報告
以下行為改變的缺陷報告被追溯地應用於以前釋出的 C 標準。
缺陷報告 | 應用於 | 釋出時的行為 | 正確的行為 |
---|---|---|---|
DR 076 | C89 | 不必要的間接不能被 & 取消 |
改為可取消 |
[編輯] 參考文獻
- C17 標準 (ISO/IEC 9899:2018)
- 6.5.2.1 陣列下標 (p: 57-58)
- 6.5.2.3 結構體和聯合體成員 (p: 58-59)
- 6.5.3.2 地址和間接運算子 (p: 59-61)
- C11 標準 (ISO/IEC 9899:2011)
- 6.5.2.1 陣列下標 (p: 80)
- 6.5.2.3 結構體和聯合體成員 (p: 82-84)
- 6.5.3.2 地址和間接運算子 (p: 88-89)
- C99 標準 (ISO/IEC 9899:1999)
- 6.5.2.1 陣列下標 (p: 70)
- 6.5.2.3 結構體和聯合體成員 (p: 72-74)
- 6.5.3.2 地址和間接運算子 (p: 78-79)
- C89/C90 標準 (ISO/IEC 9899:1990)
- 3.3.2.1 陣列下標
- 3.3.2.3 結構體和聯合體成員
- 3.3.3.2 地址和間接運算子
[編輯] 另請參閱
常見運算子 | ||||||
---|---|---|---|---|---|---|
賦值 | 遞增 遞減 |
算術 | 邏輯 | 比較 | 成員 訪問 |
其他 |
a = b |
++a |
+a |
!a |
a == b |
a[b] |
a(...) |
C++ documentation for 成員訪問運算子
|