问题
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?
回答1:
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.
回答2:
For starters you should correctlyg specify the size of the allocated memory
ar = malloc( 2 * sizeof( struct Test * ) );
This statement
*(ar+1) = &foo;
sets the second element of the allocated array of pointers to the address of the global variable foo.
It is the same as
ar[1] = &foo;
This expression
*ar
that is equivalent to the expression
ar[0]
gives the first element of the allocated array of pointers. It was not initialized. As a result this expression
*ar+1
or
ar[0] + 1
invokes undefined behavior (Adding 1 to something that was not initialized and has indeterminate value).
It seems you mean
(**(ar+1)).c = 'c';
That is the expression
*( ar + 1 )
gives the second element of the allocated dynamically array of pointers. Dereferencing it you get the address of the object foo
. Dereferencing the second time you get lvalue of the object foo itself.
Pay attention to that the expression
ar[1]
is equivalent to
*( ar + 1 )
and as you can see from this valid statement
ar[1]->c = 'c'
the above expression yields a pointer. So you need to dereference it if you want to use the operator.
**( ar + 1 )
回答3:
You want to dereference to get ar[i]
, let's do as:
(*(ar+1))->c = 'c';
来源:https://stackoverflow.com/questions/61668742/pointer-dereference-array-index