C语言中的.与->区别

  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语法无效

我编辑了答案以修复表示法,并添加了括号。

  • 11
    点赞
  • 86
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值