1、一般情况下用“.”,只需要声明一个结构体。格式是,结构体类型名+结构体名。然后用结构体名加“.”加域名就可以引用域 了。因为自动分配了结构体的内存。如同 int a;一样。
而用“->”,则要声明一个结构体的指针,还要手动开辟一个该结构体的内存,然后把返回的指针给声明的结构体指针,才能用“->”正确引用。否则内存中只分配了指针的内存,没有分配结构体的内存,导致想要的结构体实际上是不存在。这时候用“->”引用自然出错了,因为没有结构体,自然没有结构体的域了。
此外,(*a).b 等价于 a->b。
"."一般情况下读作"的”。
“->”一般读作"指向的结构体的"。
2、编辑-使用2星指针更新以获取更多相关性
假设我有一个指向结构的两星指针,该结构也包含一个指针。
typedef struct{
nodeT *ptr;
}nodeT;
nodeT example;
nodeT *test1 = &example;
nodeT *test = &test1;
如果我想要结构体中指针的地址,语法将是什么?
使用这个
&(*test->ptr)
认为解析将减少到实际的指针,然后使用&运算符返回地址。
这才是正确的语法:
&(*test)->ptr;
此外,为什么以下语法甚至无法将test指针取消引用到结构指针:
*test->ptr;
在没有*test括号的情况下,编译器返回了一条语句,通知我我正在尝试访问不属于结构或联合的内容。
阅读运算符优先级应该可以使此更清晰。
为什么C中的箭头(->)运算符可能存在? 问题并不完全相同,但是关于->的工作方式,为什么出现在其中的描述等等应该或多或少地回答这个问题。
具体地说,问题是编辑显示时使用了两星指针。
该代码无法在C中编译; 您不能在结构中使用nodeT *ptr;。 您需要typedef struct nodeT nodeT; struct nodeT { nodeT *ptr; };。
test->ptr与(*test).ptr相同
因此,我认为您需要&(test->ptr)(我不确定哪个运算符具有更高的优先级)。
您想访问什么? 如果要访问ptr的成员,则您需要的是(test->ptr)->member(可能test->ptr->member也可以使用)。
->具有更高的优先级
这是对的; (*ptr)取消引用指针。 &var获取指向变量的指针。 因此&(*ptr)有效地获得了指针指向的对象的地址,即指针。 因此ptr->与&(*ptr)->相同。
后缀运算符(例如.和->组件选择运算符)的优先级高于一元*和&。因此,*foo->bar将被解释为*(foo->bar); *运算符将应用于foo->bar的结果。同样,&bar.foo将被解释为&(bar.foo)。
因此,给出以下声明:
nodeT example;
nodeT *test1 = &example;
nodeT **test2 = &test1;
您将按以下方式访问ptr成员:
example.ptr-子表达式example具有类型nodeT;不需要间接调用,因此我们只需使用.组件选择运算符即可;
test1->ptr-子表达式test1具有类型nodeT *;有一种间接级别,因此我们需要先解除引用test1的引用,然后才能访问ptr成员。我们可以通过使用->运算符(隐式引用test1)来做到这一点,或者我们可以显式地自己取消引用test1并编写(*test1).ptr。
(*test2)->ptr-子表达式test2具有类型nodeT **;有两个间接级别,因此在访问ptr成员之前,我们需要先解除引用test2两次。如果要使用->运算符,则需要显式取消引用一次;或者,要使用.运算符-(**test2).ptr,我们需要对其进行两次取消引用。
如果左侧操作数是struct或union类型,例如example或(*test1)或(**test2),则使用.组件选择运算符。如果左侧操作数是指向struct或union类型(例如test1或(*test2))的指针,则可以使用->运算符。
现在真正有趣的是-ptr成员的类型为nodeT *,因此,如果要获取example.ptr指向的ptr,则可以编写example.ptr->ptr。子表达式example具有类型nodeT,因此我们将.组件选择运算符与其一起使用。但是,子表达式example.ptr的类型为nodeT *,因此我们需要为其使用->组件选择运算符。或者,我们必须编写(*example.ptr).ptr(记住,*example.ptr被解析为*(example.ptr))。
再往前走一步,我们可以写example.ptr->ptr->ptr,或者
(*(*example.ptr).ptr).ptr:
example.ptr
example.ptr->ptr
(*example.ptr).ptr
example.ptr->ptr->ptr
(*(*example.ptr).ptr).ptr
由于test已经是nodeT *类型,因此更加简单:
test1->ptr
(*test1).ptr
test1->ptr->ptr
(*(*test).ptr).ptr
test1->ptr->ptr->ptr
(*(*(*test1).ptr).ptr).ptr
最后,test2:
(*test2)->ptr
(**test2).ptr
(*test2)->ptr->ptr
(*(**test2).ptr).ptr
(*test2)->ptr->ptr->ptr
(*(*(**test2).ptr).ptr).ptr
鉴于:
nodeT n0 = { 0 };
nodeT n1 = { &n0 };
nodeT *test = &n1;
您可以使用:
test // Pointer to n1
&test // Pointer to test itself
test->ptr // Pointer to n0
(*test).ptr // Same as test->ptr
&test->ptr // Pointer to the element of n1 (same as n1 because of the struct def'n
test->ptr->ptr // Pointer to null
等等。
例如:
#include
#include
typedef struct nodeT nodeT;
struct nodeT { nodeT *ptr; };
static void print_addr(char * const tag, void *addr)
{
printf("%-15s = %p
", tag, addr);
}
int main(void)
{
nodeT n0 = { 0 };
nodeT n1 = { &n0 };
nodeT *test = &n1;
print_addr("test", test);
print_addr("&test", &test);
print_addr("test->ptr", test->ptr);
print_addr("(*test).ptr", (*test).ptr);
print_addr("&test->ptr", &test->ptr);
print_addr("test->ptr->ptr", test->ptr->ptr);
return 0;
}
示例输出:
test = 0x7fff58829b10
&test = 0x7fff58829b20
test->ptr = 0x7fff58829b00
(*test).ptr = 0x7fff58829b00
&test->ptr = 0x7fff58829b10
test->ptr->ptr = 0x0
由于test是指针,因此无法使用.运算符访问其字段,因此必须首先取消引用指针才能直接获取结构:
*test
之后,您可以使用.运算符访问该字段:
(*test).ptr
->运算符是取消引用结构指针的快捷方式:
test->ptr
就像最后一个表达式一样,它将获得ptr变量。如果您要的是ptr所指向的地址,那么您已被设置。
如果要使用ptr变量的地址,则需要使用&获取其地址:
(&test)->ptr
要么
&(*test).ptr
*test.ptr语法无效
我编辑了答案以修复表示法,并添加了括号。