C语言中箭头运算符(->)的使用

我正在读一本叫做《21天自学C语言》的书(我已经学会了Java和c#,所以我正在以更快的速度前进)。我正在阅读关于指针的章节,->(箭头)操作符没有解释就出现了。我认为它用于调用成员和函数(类似于.(点)操作符,但用于指针而不是成员)。但我不完全确定。

我能得到一个解释和一个代码样本吗?

586062 次浏览

foo->bar等价于(*foo).bar,即它从foo指向的结构体中获取名为bar的成员。

是的,就是这样。

它只是点版本,当你想访问一个结构/类的元素是一个指针,而不是一个引用。

struct foo
{
int x;
float y;
};


struct foo var;
struct foo* pvar;
pvar = malloc(sizeof(struct foo));


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的缩写。这就是它的全部。

Dot是一个解引用操作符,用于连接特定结构记录的结构变量。 如:< / p >

struct student
{
int s.no;
Char name [];
int age;
} s1,s2;


main()
{
s1.name;
s2.name;
}

这样,我们就可以使用点运算符来访问结构变量

我不得不对杰克的程序做了一些小改动才能让它运行起来。在声明结构指针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
#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...)

哪个看起来更好?

struct Node {
int i;
int j;
};
struct Node a, *p = &a;

在这里,要访问ij的值,我们可以使用变量a和指针p,如下所示:a.i(*p).ip->i都是相同的。

这里.是“直接选择器”,而->是“间接选择器”。

我只想在答案中加上一个“为什么”。

.是标准成员访问操作符,其优先级高于*指针操作符。

当你试图访问一个结构体的内部结构,并将其写成*foo.bar时,编译器会认为需要一个'foo'的'bar'元素(这是内存中的地址),显然这个地址没有任何成员。

因此,你需要要求编译器首先对(*foo)进行解引用,然后访问成员元素:(*foo).bar,这写起来有点笨拙,所以优秀的人提出了一个简写版本:foo->bar,这是一种通过指针操作符访问成员的方式。

#include<stdio.h>
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 < / p >

我还得补充点什么。结构与数组有点不同,因为数组是指针,而结构不是。所以要小心!

假设我写了这段无用的代码:

#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这样的指示符,它们只不过是数据块

但是由于preceedence,你不能写*ptr.kg作为访问操作符.在解引用操作符*之前求值,你会得到*(ptr.kg),这是不可能的,因为指针没有成员!编译器知道这一点,因此会发出一个错误,例如:

error: ‘ptr’ is a pointer; did you mean to use ‘->’?
printf("%d\n", *ptr.km);

相反,你使用这个(*ptr).kg,你强迫编译器1日解除对指针的引用,并允许访问数据块2日,你添加一个偏移量(指示符)来选择成员。

看看我做的这张图:

enter image description here

但是如果你有嵌套的成员,这个语法将变得不可读,因此引入了->。我认为可读性是使用它的唯一合理理由,因为ptr->kg(*ptr).kg更容易编写。

现在让我们用不同的方式来写,这样你就能更清楚地看到其中的联系。__abc0⟹__abc1⟹__abc2。在这里,我首先使用了ptr" audi的地址",即&audi,以及“参考” &(*&audi).kg0 *运算符相互抵消的事实。