指针派生数组索引

问题描述 投票:0回答:1

有这种情况。

#include <stdio.h>
#include <stdlib.h>

struct Test { char c; } foo;

int main (void) {

   struct Test **ar;
   ar=malloc(16);
   *(ar+1) = &foo;
   ar[1]->c = 'c'; //this work
  (*(*ar+1)).c = 'c'; //this does't work

   return 0;
}
        //(**(ar+1)).c='c'; --> first case

为什么上面的方法只适用于数组输入,而不是指针注销?

struct Test { char c; } foo;

int main (void) {

   struct Test **ar;
   ar=malloc(16);
   *ar=malloc(0);
   *(ar+1) = &foo;
   //(**(ar+1)).c='c';
   (*(*ar+1)).c='c'; // NOW IT WORKS --> second case
   printf("%c\n", (*(*ar+1)).c); //prints 'c'

   return 0;
}

现在即使分配了0个字节,也没有关系,因为我只是想要一个OS提供的地址,以便第一个元素被初始化。

问题:在这两种情况下,指针算术是如何工作的?

1)首先为了得到l值的? struct Test指针直接从指向的地址出发,由 ar 到l值的方法是 **ar - sizeof(struct Test**)

2)在第二种情况下,指针确实已经初始化了第一个成员。ar[0]所以它从这里开始 *ar 并以 *ar - sizeof(struct Test*).

但两个指针的大小是一样的 sizeof(struct Test**) == sizeof(struct Test*),因此不应该有算术上的差异,还是我漏掉了什么?

c pointers
1个回答
2
投票
struct Test **ar;
ar=malloc(16);
...
(*(*ar+1)).c = 'c'; //this does't work

当然是这样。正如我在评论中所说 * 优先于 + C 操作员优先. 那么,到底发生了什么?(*(*ar+1)).c? 你看

(*ar+1)

这相当于:

(ar[0] + 1)

因为... 类型 对于 ar 是一个 指针对指针 struct Test, *arar[0] 是类型 指向 struct Test. 然后你加 + 1 其中增加 sizeof (struct Test*) 到第一个指针 ar 这就是你想要的。

为什么这样做呢?操作符优先。

   *ar              /* dereference ar** leaving pointer to struct Test */

  (*ar + 1)         /* advance to next pointer - applied before next dereference */

 *(*ar + 1)         /* dereference again leaving struct Test assigned to 2nd pointer */

(*(*ar + 1)).c      /* reference member 'c' of above */

可读性是至关重要的,当你使用多层次的间接性时。使用索引符号会有很大的帮助。使用索引符号会有很大帮助。(*(*ar + 1)).c = 'c';,这样写起来就干净多了。

(*ar)[1].c = 'c';

这样可以清楚地表达出你是在引申... ar 的偏移量之前,先用 1 并再次重新引用(the [..] 提供了一个dereference,就像 '*' 来达到分配给你的第2个寄存器。


1
投票

首先,你应该正确地指定分配的内存大小

   ar = malloc( 2 * sizeof( struct Test * ) );

本声明

*(ar+1) = &foo;

将分配的指针数组的第二个元素设置为全局变量foo的地址。

这与

ar[1] = &foo;

这种表达方式

*ar

相当于

ar[0]

给出了分配的指针数组的第一个元素。它没有被初始化。结果这个表达式

*ar+1

ar[0] + 1

援引未定义的行为(在未初始化且值不确定的东西上加1)。

您的意思似乎是

(**(ar+1)).c = 'c';

这就是表达方式

*( ar + 1 )

给出了动态分配的指针数组的第二个元素。再引用它,你可以得到对象的地址。foo. Dereferencing第二次得到对象foo本身的lvalue。

请注意,表达式

ar[1]

相当于

*( ar + 1 )

从这句话可以看出

ar[1]->c = 'c'

上述表达式产生一个指针。因此,如果你想使用操作符,你需要对它进行去引用。

**( ar + 1 )

0
投票

你想去引用得到 ar[i],让我们做为。

(*(ar+1))->c = 'c';
© www.soinside.com 2019 - 2024. All rights reserved.