2

EDIT - updated with 2-star pointer for more relevancy

Say I had a two-star pointer to a structure that also contained a pointer.

typedef struct{
    nodeT *ptr;
}nodeT; 

nodeT example; 
nodeT *test1 = &example;
nodeT *test = &test1; 

If I wanted the address of the pointer in the structure, what would the syntax be? I tried this:

&(*test->ptr)

Where it was a thought that the parethesis would reduce to the actual pointer, after which the & operator is used to return the address.

Rather, I found this to be the correct syntax by trial and error:

&(*test)->ptr;

Further, I was confused why the below syntax does not work to even dereference the test pointer to the structure pointer:

*test->ptr;

It was my experience that without the parenthesis around *test the compiler returned a statement informing me I was attempting to access something not a part of a structure or union.

It must have something to do with the priority assigned to the various format elements that I am not fully aware.

Any ideas?

sherrellbc
  • 4,650
  • 9
  • 48
  • 77
  • 1
    Reading up on [operator precedence](http://en.cppreference.com/w/cpp/language/operator_precedence) should make this clearer – simonc Oct 29 '13 at 17:33
  • possible duplicate of [Why does the arrow (->) operator in C exist?](http://stackoverflow.com/q/13366083/1281433). The question's not quite the same, but the description of how `->` works, why it's there, etc., should more or less answer this question. – Joshua Taylor Oct 29 '13 at 17:40
  • Sorry, made a few edits. To be more specific, my problem was with the use of two-star pointers as the edits show. – sherrellbc Oct 29 '13 at 17:41
  • 1
    The code doesn't compile in C; you can't use `nodeT *ptr;` in the structure. You'd need `typedef struct nodeT nodeT; struct nodeT { nodeT *ptr; };`. – Jonathan Leffler Oct 29 '13 at 17:41

4 Answers4

4

test->ptr is the same that (*test).ptr

So, I think you want &(test->ptr) (I am not sure of which operator has more priority).

SJuan76
  • 24,532
  • 6
  • 47
  • 87
  • 1
    Don't know why anyone would downvote this, to I'm restoring the balance. – Spidey Oct 29 '13 at 17:33
  • Unless I was doing something wrong I tried the syntax you suggest. Perhaps I did make a mistake then. – sherrellbc Oct 29 '13 at 17:37
  • What do you want to acces? If you want to access a member of `ptr`, then what you need is `(test->ptr)->member` (probably `test->ptr->member` would work too. – SJuan76 Oct 29 '13 at 17:39
  • 1
    `->` has a higher precedence – Novak Oct 29 '13 at 17:39
  • This is correct; `(*ptr)` dereferences a pointer. `&var` gets a pointer to the variable. So `&(*ptr)` is effectively getting the address of the object pointed to by the pointer, i.e. the pointer. So `ptr->` is the same as `&(*ptr)->`. – PP. Oct 29 '13 at 17:39
3

Postfix operators such as the . and -> component selection operators have higher precedence than unary * and &. Thus, *foo->bar will be interpreted as *(foo->bar); the * operator will be applied to the result of foo->bar. Similarly, &bar.foo will be interpreted as &(bar.foo).

So, given the following declarations:

nodeT example;
nodeT *test1 = &example;
nodeT **test2 = &test1;

you would access the ptr member as follows:

  1. example.ptr - The subexpression example has type nodeT; no indirection is required, so we simply use the . component selection operator;
  2. test1->ptr - The subexpression test1 has type nodeT *; there's one level of indirection, so we need to dereference test1 before we can access the ptr member. We do that by either using the -> operator (which implicitly deferences test1), or we can explicitly dereference test1 ourselves and write (*test1).ptr.
  3. (*test2)->ptr - The subexpression test2 has type nodeT **; there are two levels of indirection, so we need to dereference test2 twice before we can access the ptr member. We need to explicitly dereference it once if we want to use the -> operator, or we dereference it twice to use the . operator - (**test2).ptr.

You use the . component selection operator if the left-hand operand is a struct or union type, such as example or (*test1) or (**test2). You use the -> operator if the left-hand operand is a pointer to a struct or union type, such as test1 or (*test2).

Now for the real fun - the ptr member has type nodeT *, so if you want to get the ptr that example.ptr points to, you would write example.ptr->ptr. The subexpression example has type nodeT, so we used the . component selection operator with it. The subexpression example.ptr, however, has type nodeT *, so we'd need to use the -> component selection operator for it. Alternately, we'd have to write (*example.ptr).ptr (remember, *example.ptr is parsed as *(example.ptr)).

Going one step farther, we could write example.ptr->ptr->ptr, or (*(*example.ptr).ptr).ptr:

example.ptr
example.ptr->ptr
(*example.ptr).ptr
example.ptr->ptr->ptr
(*(*example.ptr).ptr).ptr

Since test is already type nodeT *, it's a little more straightforward:

test1->ptr
(*test1).ptr
test1->ptr->ptr
(*(*test).ptr).ptr
test1->ptr->ptr->ptr
(*(*(*test1).ptr).ptr).ptr

And finally, test2:

(*test2)->ptr
(**test2).ptr
(*test2)->ptr->ptr
(*(**test2).ptr).ptr
(*test2)->ptr->ptr->ptr
(*(*(**test2).ptr).ptr).ptr
John Bode
  • 119,563
  • 19
  • 122
  • 198
1

Since test is a pointer, you can't access it's fields using the . operator, you have to first dereference the pointer to get the struct directly:

*test

After that, you can access the field with the . operator:

(*test).ptr

The -> operator is a shortcut to dereferencing the struct pointer:

test->ptr

That will get the ptr variable, just like the last expression. If what you want it the address pointed by ptr, then you are set.

If you want the address of the ptr variable, then you'll need to get its address by using the &:

(&test)->ptr

or

&(*test).ptr

Spidey
  • 2,508
  • 2
  • 28
  • 38
1

Given:

nodeT n0 = { 0 };
nodeT n1 = { &n0 };

nodeT *test = &n1;

You can use:

test           // Pointer to n1
&test          // Pointer to test itself
test->ptr      // Pointer to n0
(*test).ptr    // Same as test->ptr
&test->ptr     // Pointer to the element of n1 (same as n1 because of the struct def'n
test->ptr->ptr // Pointer to null

Etc.

For example:

#include <inttypes.h>
#include <stdio.h>

typedef struct nodeT nodeT;
struct nodeT { nodeT *ptr; };

static void print_addr(char * const tag, void *addr)
{
    printf("%-15s = %p\n", tag, addr);
}

int main(void)
{
    nodeT n0 = { 0 };
    nodeT n1 = { &n0 };
    nodeT *test = &n1;

    print_addr("test", test);
    print_addr("&test", &test);
    print_addr("test->ptr", test->ptr);
    print_addr("(*test).ptr", (*test).ptr);
    print_addr("&test->ptr", &test->ptr);
    print_addr("test->ptr->ptr", test->ptr->ptr);

    return 0;
}

Example output:

test            = 0x7fff58829b10
&test           = 0x7fff58829b20
test->ptr       = 0x7fff58829b00
(*test).ptr     = 0x7fff58829b00
&test->ptr      = 0x7fff58829b10
test->ptr->ptr  = 0x0
Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278