Операторы доступа к членам
Операторы доступа к членам позволяют получить доступ к членам своих операндов.
| Оператор | Название оператора | Пример | Описание |
|---|---|---|---|
[] | индекс массива | a[b] | доступ к b-му элементу массива a |
* | разыменование указателя | *a | разыменование указателя a для доступа к объекту или функции, на которую он указывает |
& | адрес | &a | создание указателя, ссылающегося на объект или функцию a |
. | доступ к члену | a.b | доступ к члену b структуры или объединения a |
-> | доступ к члену через указатель | a->b | доступ к члену b структуры или объединения, на который указывает a |
Индекс массива
Выражение индекса массива имеет вид
выражение-указатель [ выражение-целого_типа ] | (1) | |
выражение-целого_типа [ выражение-указатель ] | (2) |
где
| выражение-указатель | - | выражение типа указатель на полный объект |
| выражение-целого_типа | - | выражение целого типа |
Выражение оператора индекса массива является выражением-ссылкой, тип которого соответствует типу объекта, на который указывает выражение-указатель.
По определению, оператор индекса массива E1[E2] точно идентичен *((E1)+(E2)). Если выражение-указатель является выражением массива, оно подвергается преобразованию "ссылка-в-значение" и становится указателем на первый элемент массива.
Из-за определения сложения указателя и целого числа результатом является элемент массива с индексом, равным результату выражения-целого_типа (или, если выражение-указатель указывало на 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
Разыменование
Выражение разыменования или косвенного доступа имеет вид
* выражение-указатель |
где
| выражение-указатель | - | выражение любого типа указателя |
Если выражение-указатель является указателем на функцию, результатом оператора разыменования является обозначение функции.
Если выражение-указатель является указателем на объект, результатом является выражение-ссылка, обозначающее указанный объект.
Разыменование нулевого указателя, указателя на объект, срок жизни которого истек (висячий указатель), невыровненного указателя или указателя с неопределенным значением — это неопределенное поведение, за исключением случаев, когда оператор разыменования аннулируется применением оператора адреса к его результату, как в &*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) | |
& выражение-ссылка | (2) | |
& * выражение | (3) | |
& выражение [ выражение ] | (4) |
& и * взаимно уничтожаются, ни одно из них не вычисляется& и *, подразумеваемый в [], взаимно уничтожаются, вычисляется только сложение, подразумеваемое в [].где
| выражение-ссылка | - | выражение-ссылка любого типа, которое не является битовым полем и не имеет хранилища класса 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
}Доступ к члену
Выражение доступа к члену имеет вид
выражение . имя_члена |
где
| выражение | - | выражение типа структуры или объединения |
| имя_члена | - | идентификатор, который задает имя члена структуры или объединения, обозначенного выражением |
Выражение доступа к члену обозначает указанный член структуры или объединения, обозначенный левым операндом. Оно имеет ту же категорию значения, что и его левый операнд.
Если левый операнд имеет квалификатор const или volatile, результат также квалифицирован. Если левый операнд является атомарным, поведение неопределено.
Примечание: помимо идентификаторов, которые обозначают объекты типа структуры или объединения, следующие выражения могут иметь типы структуры или объединения: оператор присваивания, вызов функции, оператор запятой, условный оператор и составная константа.
#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
}Доступ к члену через указатель
Выражение доступа к члену через указатель имеет вид
выражение -> имя_члена |
где
| выражение | - | выражение типа указателя на структуру или объединение |
| имя_члена | - | идентификатор, который задает имя члена структуры или объединения, на который указывает выражение |
Выражение доступа к члену через указатель обозначает указанный член структуры или объединения типа, на который указывает левый операнд. Его категория значения всегда ссылка.
Если тип, на который указывает левый операнд, имеет квалификаторы 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
}Отчёты об ошибках
Ниже приведены отчёты об ошибках, изменяющие поведение, которые были применены ретроактивно к ранее опубликованным стандартам C.
| ОТЧ. ОБ ОШИБКЕ | Применено к | Поведение при публикации | Корректное поведение |
|---|---|---|---|
| ОТЧ. ОБ ОШИБКЕ 076 | C89 | излишняя косвенность не могла быть отменена & | сделано отменяемым |
Ссылки
- Стандарт C17 (ISO/IEC 9899:2018):
- 6.5.2.1 Индексирование массивов (с. 57-58)
- 6.5.2.3 Элементы структур и объединений (с. 58-59)
- 6.5.3.2 Операторы адреса и косвенного обращения (с. 59-61)
- Стандарт C11 (ISO/IEC 9899:2011):
- 6.5.2.1 Индексирование массивов (с. 80)
- 6.5.2.3 Элементы структур и объединений (с. 82-84)
- 6.5.3.2 Операторы адреса и косвенного обращения (с. 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 Операторы адреса и косвенного обращения
См. также
| Общие операторы | ||||||
|---|---|---|---|---|---|---|
| присваивания | инкремента декремента | арифметические | логические | сравнения | доступ к элементу | другие |
|
|
|
|
|
|
|
|
| Документация C++ для операторов доступа к членам |
© cppreference.com
Licensed under the Creative Commons Attribution-ShareAlike Unported License v3.0.
https://en.cppreference.com/w/c/language/operator_member_access