我正在读一本叫做《 21天自学C》的书(我已经学过Java和C#,所以我的步伐要快得多)。我正在阅读有关指针的章节,->
(箭头)运算符没有解释就出现了。我认为它用于调用成员和函数(类似于.
(点)运算符,但用于指针而不是成员)。但是我不确定。
我可以得到一个解释和一个代码示例吗?
我正在读一本叫做《 21天自学C》的书(我已经学过Java和C#,所以我的步伐要快得多)。我正在阅读有关指针的章节,->
(箭头)运算符没有解释就出现了。我认为它用于调用成员和函数(类似于.
(点)运算符,但用于指针而不是成员)。但是我不确定。
我可以得到一个解释和一个代码示例吗?
Answers:
foo->bar
等价于(*foo).bar
,即它bar
从foo
指向的结构中获取调用的成员。
->
根本就不需要该运算符,因为它等同于更易读的foo*.bar
。还要避免所有带有多余括号的类型定义函数的混乱。
foo*.bar
,(*foo).bar
两者都等于foo->bar
?那Foo myFoo = *foo; myFoo.bar
呢
对,就是那样。
当您要访问作为指针而不是引用的struct / class的元素时,它仅仅是点的版本。
struct foo
{
int x;
float y;
};
struct foo var;
struct foo* pvar;
pvar = malloc(sizeof(pvar));
var.x = 5;
(&var)->y = 14.3;
pvar->y = 22.4;
(*pvar).x = 6;
而已!
pvar = &var
呢?
我只是在答案中加上“为什么?”。
.
是标准成员访问运算符,其优先级高于 *
指针运算符。
当您尝试访问结构的内部结构时,您将其写为 *foo.bar
编译器会认为需要'foo'的'bar'元素(这是内存中的地址),并且显然,仅地址没有任何成员。
因此,您需要先让编译器先解除引用(*foo)
,然后再访问member元素:(*foo).bar
,这写起来有点笨拙,所以老兄提出了一个简写形式:foo->bar
这是指针操作符对成员的一种访问。
foo->bar
只是的简写(*foo).bar
。这里的所有都是它的。
struct Node {
int i;
int j;
};
struct Node a, *p = &a;
这里访问的价值观i
和j
我们可以使用变量a
和指针p
如下:a.i
,(*p).i
和p->i
都是一样的。
这.
是“直接选择器”,->
也是“间接选择器”。
好吧,我还必须添加一些内容。结构与数组有点不同,因为数组是指针,而结构不是指针。所以要小心!
可以说我写了这段无用的代码:
#include <stdio.h>
typedef struct{
int km;
int kph;
int kg;
} car;
int main(void){
car audi = {12000, 230, 760};
car *ptr = &audi;
}
此处的指针ptr
指向结构变量的地址(!),audi
但在地址结构旁边还具有大量数据(!)!数据块的第一个成员具有与结构本身相同的地址,您可以通过仅取消引用这样的指针来获取数据*ptr
(无花括号)。
但如果你想接取任何其他成员比第一个,你必须添加一个标志一样.km
,.kph
,.kg
足以抵消这是没有更多的基地址的数据块 ...
但是由于这个先例,您不能编写*ptr.kg
访问操作符,.
而是先评估它,然后再取消引用操作符,*
并且您会得到*(ptr.kg)
这是不可能的,因为指针没有成员!并且编译器知道这一点,因此将发出错误,例如:
error: ‘ptr’ is a pointer; did you mean to use ‘->’?
printf("%d\n", *ptr.km);
相反,你用这个(*ptr).kg
和你迫使编译器第一次取消引用指针,使接取到数据块和第二你加一个偏移量(标志),以选择成员。
检查我制作的这张图片:
但是,如果您有嵌套成员,则该语法将变得不可读,因此->
被引入。我认为可读性是使用它的唯一正当理由,因为这ptr->kg
比起编写起来容易得多(*ptr).kg
。
现在,让我们用不同的方式写这个,以便您更清楚地看到连接。(*ptr).kg
⟹ (*&audi).kg
⟹ audi.kg
。在这里,我首先使用的事实ptr
是“的地址audi
”,即“引用”和“取消引用”运算符相互抵消的&audi
事实。 &
*
我必须对Jack的程序做些小改动才能使其运行。声明结构指针pvar后,将其指向var的地址。我在Stephen Kochan的C语言编程的第242页上找到了此解决方案。
#include <stdio.h>
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
%
表示当前文件名。像这样:!gcc % && ./a.out
#include<stdio.h>
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;
}
这样,我们可以使用点运算符来访问结构变量
->
。这个问题已经回答了4。5年。