0

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?

2
  • See C Operator Precedence, '*' has higher precedence than '+' so what is happening with (*(*ar+1)).c? Commented May 7, 2020 at 22:43
  • Using index notation "this work" is ar[1][0].c = 'c'; and "this doesn't work" is ar[0][1].c = 'c', which doesn't work because you never set a value for ar[0]. In the second one you cause undefined behaviour but sometimes that manifests itself as appearing to do what you expected Commented May 7, 2020 at 23:24

3 Answers 3

2
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.

Sign up to request clarification or add additional context in comments.

3 Comments

I understand the above, makes sense, but don't understand pointer arithmetic here. Say If I do *ar=malloc(0); then this would work (*(*ar+1)).c = 'c', just because I have allocated the first element. So it goes 1 index by size struct Test*. But If I do not initilize the first element, and go directly to lvalue -> (**(ar+1)).c='c', the it goes by size struct 'Test**', but both pointers (first simple pointer, second pointer to pointer) have same size of 8 bytes. So why make difference?
Why do I add type struct Test by +1 in (*(*ar+1))? I though, that by dereferencing *ar it is now pointer-to-Test ( as you said), so by adding +1 in (*(*ar+1)) I would thing I am addting type pointer-toTest: struct Test * and not ONLY struct Test. This (*ar+1) is arithmetic in pointers, their object they points to
You have wrapped us both around the axle with the syntax :). Yes that works. *ar is pointer to struct Test; *ar + 1 will advance to next pointer; and *(*ar + 1) is struct Test assigned to 2nd pointer and finally (*(ar + 1)).c references member 'c' of above
1

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 )

11 Comments

Why do I need to initialize first pointer *ar, in order to use the seonc one which IS initialized (ar+1)=&foo ?
@Herdsman You are accessing the first uninitialized pointer in the expression *ar + 1. It is not the same as *( ar + 1 ).
So i dont have initialize the first element, in order to get to the second one by (**(ar+1)), but if i want to get to the second "throught" the first, I need to initialize the first? Because if so, then i would work
@Herdsman Please reread one more my answer. I have updated it.
I understand the above, makes sense, but don't understand pointer arithmetic here. Say If I do *ar=malloc(8); then this would work (*(*ar+1)).c = 'c', just because I have allocated the first element. So it goes 1 index by size struct Test*. But If I do not initilize the first element, and go directly to lvalue -> (**(ar+1)).c='c', the it goes by size struct Test**, but both pointers (first simple pointer, second pointer to pointer) have same size of 8 bytes. So why make difference?
|
0

You want to dereference to get ar[i], let's do as:

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

1 Comment

your edit *(ar+1) = &foo; then (*(*ar+1)).c = 'c';. It does not make sense. *arr+1 is difference to *(arr+1)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.