指针解引用数组索引 [英] 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
-sizeof(struct Test*)
到达左值.
但是两个指针的大小都相同sizeof(struct Test**) == sizeof(struct Test*)
,因此算术上不应有差异,否则我会遗漏某些东西吗?
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
,所以*ar
或ar[0]
都是 pointer指针- 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';
这清楚地表明,在应用1
的偏移量之前,您首先要对ar
进行引用,然后再次进行引用(与'*'
相同的是[..]
进行引用),以达到分配的第二个Poitner.
Having this:
#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
Why the above works only the variant with array entry and not pointer dereference?
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;
}
Now even allocated 0 bytes, that doesnt matter since I just want an address provided by OS in order to have the first element initilalized
question: how does pointer arithmetic works in both cases? As I understand the them:
1) first In order to get to lvalue of struct Test
, the pointer goes directly from the pointed address by ar
to the lvalue by **ar
- sizeof(struct Test**)
2) in second case, the pointer does have initialized the first member ar[0]
, so it starts here *ar
and goes to the lvalue by *ar
- sizeof(struct Test*)
.
But both pointers have same size sizeof(struct Test**) == sizeof(struct Test*)
, and therefor shouldn't be difference in arithmetic, or I am missing somehting?
struct Test **ar;
ar=malloc(16);
...
(*(*ar+1)).c = 'c'; //this does't work
Of course it does. As noted in my comment *
has higher precedence than +
C Operator Precedence. So what is happening in (*(*ar+1)).c
? Look at:
(*ar+1)
which is equivalent to:
(ar[0] + 1)
Since the type for ar
is a pointer-to-pointer-to struct Test
, *ar
or ar[0]
is type pointer-to struct Test
. Then you add + 1
which adds sizeof (struct Test*)
to the first pointer ar
which is what you want.
Why does that work? Operator precedence:
*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 */
Readability is critical when playing with multiple levels of indirection. Using index notation will help greatly. Instead of (*(*ar + 1)).c = 'c';
, it is much cleaner to write:
(*ar)[1].c = 'c';
That conveys clearly you are dereferencing ar
first before applying the offset of 1
and dereferencing again (the [..]
provides a dereference just as '*'
does) to reach the 2nd of your allocated poitners.
这篇关于指针解引用数组索引的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!