指针取消引用数组索引

Pointer dereference array index

有这个:

#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) 首先为了得到struct Test的左值,指针直接从ar指向的地址指向**ar-sizeof(struct Test**)的左值

2) 在第二种情况下,指针确实已经初始化了第一个成员 ar[0],所以它从这里开始 *ar 并通过 *ar - [=19= 到达左值].

但是两个指针的大小相同sizeof(struct Test**) == sizeof(struct Test*),因此在算术上应该没有区别,或者我遗漏了什么?

您想取消引用以获得 ar[i],让我们这样做:

(*(ar+1))->c = 'c';

对于初学者,您应该正确指定分配内存的大小

   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。第二次取消引用您获得对象 foo 本身的左值。

注意那个表达式

ar[1]

等同于

*( ar + 1 )

正如您从这个有效陈述中所见

ar[1]->c = 'c'

上面的表达式产生了一个指针。所以如果你想使用运算符,你需要取消引用它。

**( ar + 1 )
struct Test **ar;
ar=malloc(16);
...
(*(*ar+1)).c = 'c'; //this does't work

当然可以。如我的评论所述,* 的优先级高于 + C Operator Precedence。那么 (*(*ar+1)).c 中发生了什么?看:

(*ar+1)

相当于:

(ar[0] + 1)

因为 artypepointer-to-pointer-to struct Test, *arar[0] 是类型 指向 struct Test 的指针。然后你添加 + 1sizeof (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 的偏移量并再次取消引用([..] 提供取消引用,就像 '*' 一样)到达到您分配的点数中的第二个。