Member access operators
会员访问操作符
成员访问操作符允许访问其操作数的成员。
Operator | Operator name | Example | Description |
---|---|---|---|
[] | array subscript | ab | access the bth element of array a |
* | pointer dereference | *a | dereference the pointer a to access the object or function it refers to |
& | address of | &a | create a pointer that refers to the object or function a |
. | member access | a.b | access member b of struct or union a |
-> | member access through pointer | a->b | access member b of struct or union pointed to by a |
Subscript
数组subscrpt表达式的形式。
pointer-expression integer-expression | (1) | |
---|---|---|
integer-expression pointer-expression | (2) | |
其中
指针表达 | - | 指向完整对象的类型指针表达式 |
---|---|---|
整数表达式 | - | 整数类型的表达式 |
下标运算符表达式是lvalue表达式,其类型是指针表达式指向的对象的类型。
根据定义,下标运算符E1[E2]
与*((E1)+(E2))
。完全相同。如果pointer-expression是一个数组表达式,它将进行左值到右值的转换,并成为指向数组的第一个元素的指针。
由于指针和整数之间的加法定义,结果是数组的元素,其索引等于integer-expression的结果(或者,如果指针表达式指向某个数组的第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
int x = n[1][2]; // applying [] again to the array n[1]
printf("%c %c\n", "abc"[2], 2["abc"] // string literals are arrays too
}
输出:
3 3
c c
提领
的解引用
或间接
表达式具有形式。
* pointer-expression | | |
---|
其中
pointer-expression | - | an expression of any pointer type |
---|
如果指针表达式是指向函数的指针,则解引用运算符的结果是该函数的函数指示符。
如果指针表达式是一个指向对象的指针,则结果是一个指定指向对象的左值表达式。
取消引用空指针,指向其生命期之外的对象的指针(悬挂指针),未对齐的指针或具有不确定值的指针是未定义的行为,除非通过将地址 - of运算符应用于其结果,如在&*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
地址
表达式的地址具有这种形式。
& function | (1) | |
---|---|---|
& lvalue-expression | (2) | |
& * expression | (3) | |
& expression expression | (4) | |
1)功能的地址
2)对象的地址
3)特殊情况:&和*互相取消,没有一个人被评估
4)特例:&和[]中隐含的*相互抵消,只评估[]中暗示的加法
其中
lvalue-expression | - | an lvalue expression of any type that is not a bit field and does not have register storage class |
---|
地址 - 运算符产生其操作数的非左值地址,适合于初始化指向操作数类型的指针。如果操作数是函数指示符((1)),则结果是指向函数的指针。如果操作数是一个对象((2)),则结果是一个指向对象的指针。
如果操作数是取消引用操作符,则不采取任何操作(因此可将&应用于空指针),除非结果不是左值。
如果操作数是一个数组索引表达式,则不采取任何动作比阵列到指针转换和添加其他,所以&AN是有效的大小为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 = n+3
}
会员访问
成员访问表达式具有表单。
expression . member-name | | |
---|
其中
表达 | - | 结构或联合类型的表达式 |
---|---|---|
成员名字 | - | 一个标识符,用于命名由expression指定的结构体或联合体的成员 |
成员访问表达式指定由其左操作数指定的结构体或联合体的已命名成员。它与左操作数具有相同的值类别。
如果左操作数是const或volatile限定的,结果也是合格的。如果左操作数是原子的,则行为是未定义的。
注意:除了名称为struct或union类型的对象的标识符外,以下表达式可能具有struct或union类型:赋值,函数调用,逗号运算符,条件运算符和复合文字。
#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类型的已命名成员。其价值类别始终是左值。
如果左操作数指向的类型是const或volatile限定的,则结果也是合格的。如果左操作数指向的类型是原子的,则行为是未定义的。
#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
}