Search code examples
cpointersmallocpass-by-referencepass-by-value

can't reference a struct pointer to function unless it has been previously allocated (and freed)


I supposed to write a long explanation of the code but the explanation is already in the code below so I guess my question is: How do I get it to work without having to malloc then freeing it? or basically what is the correct way to write this in a situation like this?

#include <stdio.h>
#include <malloc.h>

struct d {
    int f;
};

struct d* rr() {
    struct d* p = malloc(sizeof (struct d*));
    p->f = 33;
    return p;
}

void rr2(struct d* p) {
    p = malloc(sizeof (struct d*));
    p->f = 22;
}



int main()
{
    //works..
    struct d* g;
    g = malloc(sizeof (struct d));
    g->f = 45;
    printf("[%i]", g->f);
    
    //works..
    g = rr();
    printf("[%i]", g->f);
    

    //below, both are same, except in this first case, g is allocated then freed..
 
    //works..
    free(g);
    rr2(g);
    printf("[%i]", g->f);
    
    //doesn't work..
    struct d *q;
    rr2(q);
    printf("[%i]", q->f);



    return 0;
}

Solution

  • For starters in the both functions

    struct d* rr() {
        struct d* p = malloc(sizeof (struct d*));
        p->f = 33;
        return p;
    }
    

    and

    void rr2(struct d* p) {
        p = malloc(sizeof (struct d*));
        p->f = 22;
    }
    

    there is a typo. It seems you mean

        struct d* p = malloc(sizeof (struct d));
                                     ^^^^^^^^
    

    and

        p = malloc(sizeof (struct d));
                           ^^^^^^^^^
    

    or

        struct d* p = malloc(sizeof ( *p ));
                                     ^^^^^
    

    and

        p = malloc(sizeof ( *p) );
                           ^^^^^
    

    As for this function

    void rr2(struct d* p) {
        p = malloc(sizeof (struct d*));
        p->f = 22;
    }
    

    then in this call

    struct d *q;
    rr2(q);
    

    the pointer q is passed to the function by value. So the function deals with a copy of the pointer q. Changing the copy within the function does not reflect on the original pointer q. It stays unchanged.

    To make the code working you have to pass the pointer by reference (indirectly through a pointer to it). In this case the function will look like

    void rr2(struct d **p) {
        *p = malloc(sizeof (struct d ));
        ( *p )->f = 22;
    }
    

    and be called like

    rr2( &q );
    

    As for this code snippet

    free(g);
    rr2(g);
    printf("[%i]", g->f);
    

    then it just invokes undefined behavior because in this statement

    printf("[%i]", g->f);
    

    there is an access to already freed memory.