Использование стрелки (->) в C
В настоящее время я изучаю C, читая книгу хорошего новичка «Teach Yourself C через 21 день» (я уже изучил Java и C #, поэтому я продвигаюсь намного быстрее). Я читал главу о указателях, и оператор -> (стрелка) подошел без объяснений. Я думаю, что он используется для вызова членов и функций (например, эквивалент оператора. (Dot), но для указателей вместо членов). Но я не совсем уверен. Могу ли я получить объяснение и образец кода?
- Безопасно ли удалить указатель NULL?
- Могу ли я взять адрес элемента «один конец прошлого» массива?
- Причина, почему бы не иметь макрос DELETE для C ++
- Псевдонимы, вызываемые разыменованием, нарушат правила строгого сглаживания
- Можно ли выделить функцию внутри массива и вернуть ее с помощью ссылки?
- Передача 2D-массива функции C ++
- Указатель на вектор
- Разница между char * str = "STRING" и char str = "STRING"?
foo->bar
эквивалентно (*foo).bar
, т. е. он получает член, называемый bar
из структуры, на которую указывает foo
.
Да это оно.
Это просто точечная версия, когда вы хотите получить доступ к элементам struct / class, который является указателем вместо ссылки.
struct foo { int x; float y; }; struct foo var; struct foo* pvar; var.x = 5; (&var)->y = 14.3; pvar->y = 22.4; (*pvar).x = 6;
Это оно!
a->b
просто коротко для (*a).b
всякий раз (тот же для функций: a->b()
является коротким для (*a).b()
).
foo->bar
является только сокращением для (*foo).bar
. Вот и все.
struct Node { int i; int j; }; struct Node a, *p = &a;
Здесь для доступа к значениям i
и j
мы можем использовать переменную a
и указатель p
следующим образом: ai
, (*p).i
и p->i
все одинаковы.
Здесь .
«Прямой выбор» и ->
«Непрямой селектор».
Я бы просто добавил к ответам «почему?».
.
является стандартным оператором доступа к члену, который имеет более высокий приоритет, чем оператор указателя *
.
Когда вы пытаетесь получить доступ к внутренним структурам, и вы написали их как *foo.bar
тогда компилятор думал бы, что хочет элемент «bar» из «foo» (который является адресом в памяти) и, очевидно, что простой адрес не имеет любых членов.
Таким образом, вам нужно попросить компилятор сначала разыменовать whith (*foo)
а затем получить доступ к элементу-члену: (*foo).bar
, который немного (*foo).bar
писать, поэтому хорошие люди придумали сокращенную версию: foo->bar
который является своего рода доступом к членству оператором указателя.
Я должен был внести небольшое изменение в программу Джека, чтобы заставить ее работать. После объявления указателя struct pvar укажите его на адрес var. Я нашел это решение на стр. 242 программирования Стивена Кочана в C.
#include int main() { struct foo { int x; float y; }; struct foo var; struct foo* pvar; pvar = &var; var.x = 5; (&var)->y = 14.3; printf("%i - %.02f\n", var.x, (&var)->y); pvar->x = 6; pvar->y = 22.4; printf("%i - %.02f\n", pvar->x, pvar->y); return 0; }
Запустите это в vim со следующей командой:
:!gcc -o var var.c && ./var
Вывод:
5 - 14.30 6 - 22.40
#include int main() { struct foo { int x; float y; } var1; struct foo var; struct foo* pvar; pvar = &var1; /* if pvar = &var; it directly takes values stored in var, and if give new > values like pvar->x = 6; pvar->y = 22.4; it modifies the values of var object..so better to give new reference. */ var.x = 5; (&var)->y = 14.3; printf("%i - %.02f\n", var.x, (&var)->y); pvar->x = 6; pvar->y = 22.4; printf("%i - %.02f\n", pvar->x, pvar->y); return 0; }
Оператор ->
делает код более читаемым, чем оператор *
в некоторых ситуациях.
Например: (цитируется в проекте EDK II )
typedef EFI_STATUS (EFIAPI *EFI_BLOCK_READ)( IN EFI_BLOCK_IO_PROTOCOL *This, IN UINT32 MediaId, IN EFI_LBA Lba, IN UINTN BufferSize, OUT VOID *Buffer ); struct _EFI_BLOCK_IO_PROTOCOL { /// /// The revision to which the block IO interface adheres. All future /// revisions must be backwards compatible. If a future version is not /// back wards compatible, it is not the same GUID. /// UINT64 Revision; /// /// Pointer to the EFI_BLOCK_IO_MEDIA data for this device. /// EFI_BLOCK_IO_MEDIA *Media; EFI_BLOCK_RESET Reset; EFI_BLOCK_READ ReadBlocks; EFI_BLOCK_WRITE WriteBlocks; EFI_BLOCK_FLUSH FlushBlocks; };
Структура _EFI_BLOCK_IO_PROTOCOL
содержит 4 элемента указателя функций.
Предположим, что у вас есть переменная struct _EFI_BLOCK_IO_PROTOCOL * pStruct
, и вы хотите использовать старый добрый оператор *
чтобы вызвать его указатель на функцию-член. Вы получите код следующим образом:
(*pStruct).ReadBlocks(...arguments...)
Но с помощью оператора ->
вы можете написать вот так:
pStruct->ReadBlocks(...arguments...)
.
Что выглядит лучше?
Dot – это оператор разыменования и используется для связывания структурной переменной для конкретной записи структуры. Например:
struct student { int s.no; Char name []; int age; } s1,s2; main() { s1.name; s2.name; }
Таким образом, мы можем использовать оператор точки для доступа к структурной переменной
#include struct examp{ int number; }; struct examp a,*b=&a;`enter code here` main() { a.number=5; /* a.number,b->number,(*b).number produces same output. b->number is mostly used in linked list*/ printf("%d \n %d \n %d",a.number,b->number,(*b).number); }
выход 5 5 5