Member access operators
Операторы доступа к членам позволяют обращаться к членам своих операндов.
| Оператор | Название оператора | Пример | Описание |
|---|---|---|---|
| [ ] | array subscript | a [ b ] | доступ к b -му элементу массива a |
| * | pointer dereference | * a | разыменовать указатель a для доступа к объекту или функции, на которую он ссылается |
| & | address of | & a | создать указатель, который ссылается на объект или функцию a |
| . | member access | a. b | доступ к члену b структуры struct или объединения union a |
| - > | member access through pointer | a - > b | доступ к члену b структуры struct или объединения union , на которые указывает a |
Содержание |
Нижний индекс
Выражение индексации массива имеет вид
pointer-expression
[
integer-expression
]
|
(1) | ||||||||
integer-expression
[
pointer-expression
]
|
(2) | ||||||||
где
| pointer-expression | - | выражение типа указатель на полный объект |
| integer-expression | - | выражение целочисленного типа |
Выражение оператора индексации является lvalue-выражением , тип которого совпадает с типом объекта, на который указывает pointer-expression .
По определению, оператор индексации E1 [ E2 ] точно идентичен выражению * ( ( E1 ) + ( E2 ) ) . Если pointer-expression является выражением массива, оно подвергается преобразованию lvalue-to-rvalue и становится указателем на первый элемент массива.
В соответствии с определением сложения указателя и целого числа , результатом является элемент массива с индексом, равным результату 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
Разыменование
Выражение разыменования или косвенной адресации имеет вид
*
pointer-expression
|
|||||||||
` не переведен (оператор разыменования `*`)
- Термин "pointer-expression" не переведен, так как это C++ специфический термин
- Форматирование и структура таблицы полностью сохранены
где
| pointer-expression | - | любое выражение указательного типа |
Если pointer-expression является указателем на функцию, результатом оператора разыменования является обозначение функции для этой функции.
Если pointer-expression является указателем на объект, результатом будет lvalue выражение , которое обозначает указываемый объект.
Разыменование нулевого указателя, указателя на объект вне времени его жизни (висячий указатель), невыровненного указателя или указателя с неопределённым значением является неопределённым поведением, за исключением случаев, когда оператор разыменования аннулируется применением оператора взятия адреса к его результату, как в & * E .
Вывод:
*p = 1 *p = 7
Адрес
Выражение взятия адреса имеет вид
&
функция
|
(1) | ||||||||
&
lvalue-выражение
|
(2) | ||||||||
&
*
выражение
|
(3) | ||||||||
&
выражение
[
выражение
]
|
(4) | ||||||||
&
и
*
взаимно уничтожаются, ни один из них не вычисляется
&
и
*
, подразумеваемый в
[]
, взаимно уничтожаются, вычисляется только сложение, подразумеваемое в
[]
.
где
| lvalue-expression | - | выражение lvalue любого типа, которое не является битовым полем и не имеет класса хранения register |
Оператор взятия адреса создаёт не-lvalue адрес своего операнда, подходящий для инициализации указателя на тип операнда. Если операнд является обозначением функции (1) , результат представляет собой указатель на функцию. Если операнд является объектом (2) , результат представляет собой указатель на объект.
Если операнд является оператором разыменования, никаких действий не предпринимается (так что допустимо применять &* к нулевому указателю), за исключением того, что результат не является lvalue.
Если операнд является выражением индекса массива, никаких действий, кроме преобразования массива в указатель и сложения, не выполняется, поэтому &a[N] допустимо для массива размера 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 | - | выражение типа struct или union |
| member-name | - | идентификатор , который обозначает член структуры или объединения, заданного expression |
Выражение доступа к члену обозначает именованный член 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; // ок, изменяет член структуры s int n = f().x; // f() - выражение типа struct s // f().x = 1; // Ошибка: это выражение доступа к члену не является lvalue const struct s sc; // sc.x = 3; // Ошибка: sc.x является константой, нельзя присвоить значение union { int x; double d; } u = {1}; u.d = 0.1; // изменяет активный член объединения }
Доступ к члену через указатель
Выражение доступа к члену имеет вид
выражение
->
имя-члена
|
|||||||||
где
| expression | - | выражение типа pointer на struct или union |
| member-name | - | identifier который называет член структуры или объединения, на которые указывает expression |
Выражение доступа к члену через указатель обозначает именованный член 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 Индексация массивов (стр: 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 Операторы взятия адреса и косвенной адресации
Смотрите также
| Общие операторы | ||||||
|---|---|---|---|---|---|---|
| присваивание |
инкремент
декремент |
арифметические | логические | сравнения |
доступ к членам
доступа |
другие |
|
a
=
b
|
++
a
|
+
a
|
!
a
|
a
==
b
|
a
[
b
]
|
a
(
...
)
|
|
Документация C++
для
Операторов доступа к членам
|