Primemaster
Primemaster

Reputation: 312

Pass pointer to struct by reference in C

Take in mind the following piece of code:

#include <stdio.h>
#include <stdlib.h>

typedef struct
{
    int a;
    int b;
    int c;
}A;

A *test;

void init(A* a)
{
    a->a = 3;
    a->b = 2;
    a->c = 1;
}
int main()
{
    test = malloc(sizeof(A));
    init(test);
    printf("%d\n", test->a);
    return 0;
}

It runs fine! Now imagine that I want to use the malloc function outside the main itself without returning a pointer to the struct. I would put malloc inside init and pass test adress. But this doesnt seem to work.

#include <stdio.h>
#include <stdlib.h>

typedef struct
{
    int a;
    int b;
    int c;
}A;

A *test;

void init(A** a)
{
    *a = malloc(sizeof(A));
    *a->a = 3;
    *a->b = 2;
    *a->c = 1;
}
int main()
{
    init(&test);
    printf("%d\n", test->a);
    return 0;
}

It keeps telling me that int a(or b/c) is not a member of the struct A when I use the pointer.

Upvotes: 3

Views: 8057

Answers (4)

James K. Lowden
James K. Lowden

Reputation: 7837

Even though it's not a direct answer to your question, since we're in the vicinity of initialization I'd like to point out that C11 gives you a nicer syntax to initialize structs:

void init(A **a)
{
    A *ret = malloc(sizeof *ret); // we want the size that is referenced by ret
    if (ret != NULL) { // you should check the return of malloc
        *ret = (A) {3, 2, 1};
        // or
        *ret = (A) { .a = 3, .b = 2, .c = 1 };
    }
    *a = ret;
}

Another advantage is that any uninitialized members are zeroed.

Upvotes: 4

Stargateur
Stargateur

Reputation: 26727

You must add parenthesis:

void init(A **a)
{
    *a = malloc(sizeof(A)); // bad you don't verify the return of malloc
    (*a)->a = 3;
    (*a)->b = 2;
    (*a)->c = 1;
}

But it's good practice to do this:

void init(A **a)
{
    A *ret = malloc(sizeof *ret); // we want the size that is referenced by ret
    if (ret != NULL) { // you should check the return of malloc
        ret->a = 3;
        ret->b = 2;
        ret->c = 1;
    }
    *a = ret;
}

Upvotes: 5

David Choweller
David Choweller

Reputation: 1050

Your problem is operator precedence. The -> operator has higher precedence than the * (dereference) operator, so *a->a is read as if it is *(a->a). Change *a->a to (*a)->a:

#include <stdio.h>
#include <stdlib.h>

typedef struct
{
    int a;
    int b;
    int c;
}A;

A *test;

void init(A** a)
{
    *a = malloc(sizeof(A));
    (*a)->a = 3;
    (*a)->b = 2;
    (*a)->c = 1;
}
int main()
{
    init(&test);
    printf("%d\n", test->a);
    return 0;
}

Upvotes: 6

Kerrek SB
Kerrek SB

Reputation: 477060

You need to write (*a)->a = 3; for reasons of precedence.

Upvotes: 4

Related Questions