名前空間
変種
操作

メンバーアクセス演算子

From cppreference.com
< c‎ | language

メンバアクセス演算子は、オペランドのメンバにアクセスすることを可能にします。

Operator 演算子名 説明
[] 配列添え字 a[b] 配列ab番目の要素にアクセス
* ポインタ間接参照 *a ポインタaを間接参照して、それが指すオブジェクトまたは関数にアクセス
& アドレス演算子 &a オブジェクトまたは関数aを指すポインタを作成
. メンバアクセス a.b 構造体または共用体aのメンバbにアクセス
-> ポインタ経由のメンバアクセス a->b ポインタで指されている構造体または共用体のメンバbにアクセス

目次

[編集] 添え字

配列添え字式は次の形式をとります。

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

ここで、

ポインタ式 - 完全なオブジェクトを指すポインタ型の
整数式 - 整数型の

添え字演算子式は、ポインタ式が指すオブジェクトの型を持つlvalue式です。

定義により、添え字演算子 E1[E2]*((E1)+(E2)) と完全に等価です。ポインタ式が配列式である場合、それはlvalueからrvalueへの変換を受け、配列の最初の要素へのポインタになります。

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

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

#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

[編集] 間接参照

間接参照またはポインタ参照式は次の形式をとります。

* ポインタ式

ここで、

ポインタ式 - 任意のポインタ型の

ポインタ式が関数のポインタである場合、間接参照演算子の結果は、その関数への関数指定子です。

ポインタ式がオブジェクトへのポインタである場合、結果は、指されているオブジェクトを指定するlvalue式です。

ヌルポインタ、その寿命外のオブジェクトへのポインタ(ダングリングポインタ)、 misalignedポインタ、または不定値を持つポインタの間接参照は未定義の動作です。ただし、間接参照演算子が、その結果にアドレス演算子を適用することによって無効化される場合、例えば &*E のような場合を除きます。

#include <stdio.h>
int main(void)
{
    int n = 1;
    int* p = &n;
    printf("*p = %d\n", *p); // the value of *p is what's stored in n
    *p = 7; // *p is lvalue
    printf("*p = %d\n", *p);
}

出力

*p = 1
*p = 7

[編集] アドレス演算子

アドレス演算子式は次の形式をとります。

& 関数 (1)
& lvalue式 (2)
& * (3)
& [ ] (4)
1) 関数のアドレス
2) オブジェクトのアドレス
3) 特別なケース:&*は互いに打ち消し合い、どちらも評価されない
4) 特別なケース:&[]で暗黙的に示される*は互いに打ち消し合い、`[]`で暗黙的に示される加算のみが評価される。

ここで、

lvalue式 - ビットフィールドではなく、register記憶クラスを持たない、任意の型のlvalue

アドレス演算子は、オペランドの非lvalueアドレスを生成し、オペランドの型へのポインタの初期化に適しています。オペランドが関数指定子 (1) である場合、結果は関数へのポインタです。オペランドがオブジェクト (2) である場合、結果はオブジェクトへのポインタです。

オペランドが間接参照演算子である場合、何もアクションは取られません(そのため、nullポインタに`&*`を適用しても問題ありません)。ただし、結果はlvalueではありません。

オペランドが配列添え字式である場合、配列からポインタへの変換と加算以外の何もアクションは取られません。そのため、`&a[N]`はサイズNの配列に対して有効です(配列の末尾の1つ先のポインタを取得することは可能ですが、それを間接参照することはできません。ただし、この式では間接参照は互いに打ち消し合います)。

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
}

[編集] メンバアクセス

メンバアクセス式は次の形式をとります。

. メンバ名

ここで、

- 構造体または共用体型の
メンバ名 - によって指定される構造体または共用体のメンバを命名する識別子

メンバアクセス式は、左オペランドによって指定される構造体または共用体の指定されたメンバを指します。その値カテゴリは、左オペランドと同じです。

左オペランドが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
}

[編集] ポインタ経由のメンバアクセス

メンバアクセス式は次の形式をとります。

-> メンバ名

ここで、

- ポインタから構造体または共用体への型の
メンバ名 - で指される構造体または共用体のメンバを命名する識別子

ポインタ経由のメンバアクセス式は、左オペランドによって指される構造体または共用体型の指定されたメンバを指します。その値カテゴリは常にlvalueです。

左オペランドによって指される型が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 適用対象 公開された動作 正しい動作
DR 076 C89 不要な間接参照が&で打ち消せなかった 打ち消せるように変更

[編集] 参照

  • C17標準 (ISO/IEC 9899:2018)
  • 6.5.2.1 Array subscripting (p: 57-58)
  • 6.5.2.3 Structure and union members (p: 58-59)
  • 6.5.3.2 Address and indirection operators (p: 59-61)
  • C11標準 (ISO/IEC 9899:2011)
  • 6.5.2.1 Array subscripting (p: 80)
  • 6.5.2.3 Structure and union members (p: 82-84)
  • 6.5.3.2 Address and indirection operators (p: 88-89)
  • C99標準 (ISO/IEC 9899:1999)
  • 6.5.2.1 Array subscripting (p: 70)
  • 6.5.2.3 Structure and union members (p: 72-74)
  • 6.5.3.2 Address and indirection operators (p: 78-79)
  • C89/C90標準 (ISO/IEC 9899:1990)
  • 3.3.2.1 Array subscripting
  • 3.3.2.3 Structure and union members
  • 3.3.3.2 Address and indirection operators

[編集] 関連項目

共通の演算子
代入 インクリメント
デクリメント
算術 論理 比較 メンバ
アクセス
その他

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++ドキュメントメンバアクセス演算子
English 日本語 中文(简体) 中文(繁體)