3

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.

4
  • I bet that's not what it's telling you. What's the actual error message? Commented Jan 17, 2017 at 0:08
  • @melpomene request for member 'a' in something not a structure or union Commented Jan 17, 2017 at 0:10
  • 3
    See? It doesn't even mention struct A. It says the thing you're trying to use isn't a struct at all. (As the answers below explain, your code is getting parsed as *(a->a), a->a is the same as (*a).a, and the type of *a is A *; i.e. the compiler thinks you're trying to access members of a pointer, which makes no sense.) Commented Jan 17, 2017 at 0:13
  • and just an fyi,, there is no pass-by-reference in C,, it's all pass-by-value. In this case, you're passing a pointer by value to init where it's dereferenced and operated on. Commented Jan 17, 2017 at 0:22

4 Answers 4

6

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;
}
Sign up to request clarification or add additional context in comments.

Comments

5

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;
}

Comments

4

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

1 Comment

Wow didn't really think it was a question of syntax. Thank you!
4

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.

1 Comment

It's very interesting an user friendly doc is here. But I want to know if it's create a temporary variable or if it's only affect the struct.

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.