Namespaces
Variants

Member access operators

From cppreference.net

成员访问运算符允许访问其操作数的成员。

运算符 运算符名称 示例 描述
[ ] 数组下标 a [ b ] 访问数组 a 的第 b 个元素
* 指针解引用 * a 解引用指针 a 以访问其指向的对象或函数
& 取地址 & a 创建指向对象或函数 a 的指针
. 成员访问 a. b 访问 结构体 联合体 a 的成员 b
- > 指针成员访问 a - > b 访问由 a 指向的 结构体 联合体 的成员 b

目录

下标运算符

数组下标表达式的形式为

指针表达式 [ 整数表达式 ] (1)
整数表达式 [ 指针表达式 ] (2)

其中

pointer-expression - 指向完整对象的 表达式
integer-expression - 整数类型的 表达式

下标运算符表达式是一种 左值表达式 ,其类型为 pointer-expression 所指向对象的类型。

根据定义,下标运算符 E1 [ E2 ] 完全等同于 * ( ( E1 ) + ( E2 ) ) 。若 pointer-expression 是数组表达式,它会经历 左值到右值转换 并成为指向数组首元素的指针。

根据 指针与整数的加法运算 定义,运算结果将指向索引值等于 整数表达式 计算结果的数组元素(或者,如果 指针表达式 原本指向某个数组的第i个元素,则结果元素的索引值为i加上 整数表达式 的计算结果)

注意:有关多维数组的详细信息,请参阅 array

#include <stdio.h>
int main(void)
{
    int a[3] = {1,2,3};
    printf("%d %d\n", a[2],  // n == 3
                      2[a]); // 相同,n == 3
    a[2] = 7; // 下标是左值
    int n[2][3] = {{1,2,3},{4,5,6}};
    int (*p)[3] = &n[1]; // n的元素是数组
    printf("%d %d %d\n", (*p)[0], p[0][1], p[0][2]); // 通过p访问n[1][]
    int x = n[1][2]; // 对数组n[1]再次应用[]
    printf("%d\n", x);
    printf("%c %c\n", "abc"[2], 2["abc"]); // 字符串字面量也是数组
}

输出:

3 3
4 5 6
6
c c

解引用

解引用 间接寻址 表达式的形式为

* 指针表达式

其中

pointer-expression - 任意指针类型的 表达式

如果 pointer-expression 是指向函数的指针,则解引用运算符的结果是表示该函数的函数指示符。

如果 pointer-expression 是指向对象的指针,则结果为指向该对象的 左值表达式

解引用空指针、指向生命周期外对象的指针(悬垂指针)、未对齐指针或具有不确定值的指针是未定义行为,除非通过对其结果应用取址运算符来使解引用操作无效,例如 & * 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 - 任意类型的 左值 表达式,该类型不能是 位域 且不能具有 register 存储类

取地址运算符生成其操作数的 非左值 地址,适用于初始化指向操作数类型的指针。若操作数为函数指示符 (1) ,则结果为指向函数的指针。若操作数为对象 (2) ,则结果为指向对象的指针。

如果操作数是解引用运算符,则不执行任何操作(因此可以对空指针应用 &*),但结果不是左值。

如果操作数是数组索引表达式,除了数组到指针的转换和加法运算外不会执行其他操作,因此对于大小为N的数组,&a[N]是有效的(获取尾后指针是允许的,解引用它是不允许的,但在此表达式中解引用操作被抵消)。

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 - 一个 结构体 联合体 类型的表达式
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; // 正确:修改s的成员
    int n = f().x; // f()是struct s类型的表达式
//  f().x = 1; // 错误:该成员访问表达式不是左值
    const struct s sc;
//  sc.x = 3;  // 错误:sc.x是常量,不可被赋值
    union { int x; double d; } u = {1};
    u.d = 0.1; // 修改联合体的活跃成员
}

通过指针进行成员访问

成员访问表达式具有以下形式

表达式 -> 成员名称

其中

expression - 指向 结构体 联合体 指针 类型表达式
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; // 通过指针修改 s.x 的值
    printf("%d\n", p->x); // 输出 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 数组下标(第70页)
  • 6.5.2.3 结构与联合成员(第72-74页)
  • 6.5.3.2 取址与间接运算符(第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++ 文档 关于 成员访问运算符