指针取消引用数组索引
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)
因为 ar
的 type 是 pointer-to-pointer-to struct Test
, *ar
或 ar[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
的偏移量并再次取消引用([..]
提供取消引用,就像 '*'
一样)到达到您分配的点数中的第二个。
有这个:
#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)
因为 ar
的 type 是 pointer-to-pointer-to struct Test
, *ar
或 ar[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
的偏移量并再次取消引用([..]
提供取消引用,就像 '*'
一样)到达到您分配的点数中的第二个。