Namespaces
Variants

Member access operators

From cppreference.net

メンバーアクセス演算子は、そのオペランドのメンバーへのアクセスを許可します。

演算子 演算子名 説明
[ ] array subscript a [ b ] 配列 a b 番目の要素にアクセスする
* pointer dereference * a ポインタ a を間接参照し、それが指すオブジェクトまたは関数にアクセスする
& address of & a オブジェクトまたは関数 a を参照するポインタを作成する
. member access a. b struct または union a のメンバ b にアクセスする
- > member access through pointer a - > b a が指す struct または union のメンバ b にアクセスする

目次

添字演算子

配列添字式は以下の形式を持ちます

ポインタ式 [ 整数式 ] (1)
整数式 [ ポインタ式 ] (2)

ここで

pointer-expression - 完全オブジェクトへのポインタ型の式
integer-expression - 整数型の式

添字演算子式は、 lvalue式 であり、その型は pointer-expression によって指されるオブジェクトの型です。

定義により、添字演算子 E1 [ E2 ] * ( ( E1 ) + ( E2 ) ) と完全に同一です。 pointer-expression が配列式の場合、それは 左辺値から右辺値への変換 を受け、配列の最初の要素へのポインタとなります。

ポインタと整数の 加算の定義 により、その結果は integer-expression の結果に等しいインデックスを持つ配列の要素となる(または、 pointer-expression が何らかの配列のi番目の要素を指していた場合、結果のインデックスはiに integer-expression の結果を加えた値となる)

注: 多次元配列の詳細については array を参照してください。

#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

デリファレンス

dereference または indirection 式は次の形式を持ちます

* ポインター式

ここで

pointer-expression - 任意のポインタ型の

pointer-expression が関数へのポインタである場合、間接参照演算子の結果はその関数の関数指示子となります。

pointer-expression がオブジェクトへのポインタである場合、結果は指し示すオブジェクトを表す lvalue式 となります。

ヌルポインタ、寿命外のオブジェクトへのポインタ(ダングリングポインタ)、不適切にアライメントされたポインタ、または不定値を持つポインタの逆参照は未定義動作です。ただし、逆参照演算子の結果にアドレス取得演算子を適用して無効化する場合(例: & * E のように)は例外です。

#include <stdio.h>
int main(void)
{
    int n = 1;
    int* p = &n;
    printf("*p = %d\n", *p); // *pの値はnに格納されている値です
    *p = 7; // *pは左辺値です
    printf("*p = %d\n", *p);
}

出力:

*p = 1
*p = 7

アドレス取得演算子

アドレス取得式の形式は以下の通りです。

& 関数 (1)
& 左辺値式 (2)
& * (3)
& [ ] (4)
1) 関数のアドレス
2) オブジェクトのアドレス
3) 特殊ケース: & * は互いに打ち消し合い、どちらも評価されません
4) 特殊ケース: & [] 内で暗示される * は互いに打ち消し合い、 [] 内で暗示される加算のみが評価されます。

ここで

lvalue-expression - lvalue 式で、 bit-field ではなく、 register ストレージクラスを持たない任意の型の式

アドレス取得演算子は、そのオペランドの 非左値 アドレスを生成し、オペランドの型を指すポインタの初期化に適しています。オペランドが関数指示子 (1) の場合、結果は関数へのポインタとなります。オペランドがオブジェクト (2) の場合、結果はオブジェクトへのポインタとなります。

被演算子が逆参照演算子の場合、何も行われません(したがって、&*をヌルポインタに適用しても問題ありません)。ただし、結果は左辺値ではありません。

被演算子が配列インデックス式である場合、配列からポインタへの変換と加算以外のアクションは行われないため、サイズNの配列に対して&a[N]は有効です(末尾を1つ超えたポインタの取得は可能ですが、間接参照はできません。ただし、この式では間接参照が相殺されます)。

int f(char c) { return c;}
int main(void)
{
   int n = 1;
   int *p = &n; // オブジェクトnのアドレス
   int (*fp)(char) = &f; // 関数fのアドレス
   int a[3] = {1,2,3};
   int *beg=a, *end=&a[3]; // end = a+3 と同じ
}

メンバーアクセス

メンバアクセス式は以下の形式を持ちます

. メンバー名

ここで

expression - struct または union 型の式
member-name - expression で指定されるstructまたはunionのメンバーを指名する 識別子

メンバアクセス式は、左オペランドによって指定された struct または union の名前付きメンバを指定します。これは左オペランドと同じ value category を持ちます。

左側のオペランドが const または volatile 修飾されている場合、結果も同様に修飾されます。左側のオペランドが atomic の場合、動作は未定義です。

注記: 構造体または共用体型のオブジェクトを名前付ける識別子に加えて、以下の式が構造体または共用体型を持つ可能性があります: assignment function call comma operator conditional operator 、および compound literal

#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: sのメンバを変更
    int n = f().x; // f()はstruct s型の式
//  f().x = 1; // エラー: このメンバアクセス式は左辺値ではない
    const struct s sc;
//  sc.x = 3;  // エラー: sc.xはconstであり、代入できない
    union { int x; double d; } u = {1};
    u.d = 0.1; // unionのアクティブメンバを変更
}

ポインタを通じたメンバーアクセス

メンバアクセス式は以下の形式を持ちます

-> メンバー名

ここで

expression - pointer 型の式で、 struct または union を指すもの
member-name - identifier で、 expression が指すstructまたはunionのメンバーを指定するもの

メンバアクセス(ポインタ経由)式は、左オペランドが指す struct または union 型の名前付きメンバを指定します。その値カテゴリは常に lvalue です。

左側のオペランドが指す型が const または volatile 修飾されている場合、結果も同様に修飾されます。左側のオペランドが指す型が atomic である場合、動作は未定義です。

#include <stdio.h>
struct s {int x;};
int main(void)
{
    struct s s={1}, *p = &s;
    p->x = 7; // ポインタを通じてs.xの値を変更
    printf("%d\n", p->x); // 7を出力
}

不具合報告

以下の動作変更に関する欠陥報告書は、以前に公開されたC規格に対して遡及的に適用されました。

DR 適用対象 公開時の動作 正しい動作
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 + = b
a - = b
a * = b
a / = b
a % = b
a & = b
a | = b
a ^ = b
a <<= b
a >>= b

++ a
-- a
a ++
a --

+ a
- a
a + b
a - b
a * b
a / b
a % b
~a
a & b
a | b
a ^ b
a << b
a >> b

! a
a && b
a || b

a == b
a ! = b
a < b
a > b
a <= b
a >= b

a [ b ]
* a
& a
a - > b
a. b

a ( ... )
a, b
( type ) a
a ? b : c
sizeof


_Alignof
(C11以降)
(C23まで)

alignof
(C23以降)

C++ documentation for Member access operators