sherrellbc
sherrellbc

Reputation: 4853

'->' operator in C and how it's used

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?

Upvotes: 2

Views: 524

Answers (4)

Spidey
Spidey

Reputation: 2589

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

Upvotes: 1

John Bode
John Bode

Reputation: 123558

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

Upvotes: 3

Jonathan Leffler
Jonathan Leffler

Reputation: 754590

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

Upvotes: 1

SJuan76
SJuan76

Reputation: 24895

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

Upvotes: 4

Related Questions