Home > other >  Passing struct pointer to two functions and then calling malloc
Passing struct pointer to two functions and then calling malloc

Time:03-10

I have a struct in my main function. I pass that pointer to another function which does some stuff and if conditions are met, it passes it to another function to get filled out. When returning to the main function the t struct contains none of the data mydata that was copied into it.

typedef struct _t {
    int one;
    int two;
    int three;
    int four;
} T;

void second(T *t) {
    t = malloc(20);
    memcpy(t, mydata, 20);
}

void first(T *t) {
    second(t);
}

int main() {
    T t;

    first(t);
}

Do I need to be working with double pointers here? If the address of t was 0x1000 and I passed it to first() then wouldn't referencing t just be 0x1000? And same as if I pass the pointer to second()?

CodePudding user response:

In this answer, I assume that, for reasons not shown, you do in fact need to make a dynamic memory allocation. If that is not the case, the only changes that need to be made are replacing first(t); with first(&t);, and removing t = malloc(20);.


The first problem to fix is that t in main should have the type T *, not T. You are making a dynamic memory allocation, and seem to want to store that pointer in t, so you would need: T *t;.

The second problem is that you want to manipulate the value of t in main, but are passing it by value to first. Instead, you need to pass a pointer to t into first: first(&t);.

Fixing both of these, you now pass a pointer to a pointer to T (the type of &t) into first and second, so you need to change their signatures to be, respectively, void first(T **t) and void second(T **t).

Applying both changes, as well as making some small style tweaks, we get:

typedef struct T {
    int one;
    int two;
    int three;
    int four;
} T;

void second(T **t_ptr) {
    *t_ptr = malloc(20);
    memcpy(*t_ptr, mydata, 20);
}

void first(T **t_ptr) {
    second(t_ptr);
}

int main() {
    T *t;

    first(&t);
}

Another thing that's missing, and needs to be added, is checking for the success of malloc, but I haven't added that to the above code.

Also, what you've shown in the question shouldn't compile; you're passing a struct to a function that accepts a pointer.

CodePudding user response:

Your problems are common to new C developers. And actually you have two of them.

The first problem is that you pass your structure by value. The first function is declared to receive a pointer to T but you pass t and not &t (which is the address of t - and this is what you want when a function accepts a pointer).

However there is still another problem so that even if you change your code as suggested above it will still not work correctly. second allocates memory using malloc. The function receives T as a pointer T *t. You assign the output of malloc to t in effect overwriting what t points to (and if t was previously allocated you will leak memory here).

Bellow you can see a correct code for what you want.

typedef struct _t {
    int one;
    int two;
    int three;
    int four;
} T;

/* Make sure we have some data to initialize */
T mydata = {0};

/* 
We take a pointer to a pointer and change what the external pointer points to. */
In our example when this function is called *ppt is NULL 
and t is a pointer to t in main() 
*/ 
void second(T **ppt) {
    /* 
     We never calculate the size of structures by hand. It can change depending on 
     OS and architecture. Best let the compiler do the work.
    */
    *ppt = (T*)malloc(sizeof(T));
    memcpy(*ppt, &mydata, sizeof(T));
}

void first(T **ppt) {
    /* Make sure we don't leave dangling pointers. */
    if (NULL != *ppt)
        free(*ppt);
    second(ppt);
}

int main() {
    
    T *t = NULL; /* A pointer to our data */

    /*
     We pass a pointer to our pointer so that the function can change the value it 
     holds
    */
    first(&t);

    /* Always do an explicit return if the type of the function is not void */
    return 0;
}

How to understand what is going on:

First we declare t as a pointer to a memory holding a type T and we make sure we initialize the pointer to point to NULL (which is a convention meaning that the pointer is not initialized).

We have a function that will allocate the memory for us using malloc. malloc allocates memory from the heap and returns the address of that memory. (In reality a pointer is just a variable holding an address in memory). We want to place that address in t declared in main(). To do so we need to pass to the allocating function the address of t so it can be modified. To do this we use the address of operator - &. This is why we call the function like this first(&t).

Our allocating function accepts a pointer to a pointer. This is because we want to change the address t points to. So we declared the parameter as T **ppt. It holds the address of the pointer *t in main. In the function we dereference the pointer to the pointer to get the original pointer we want to assign the address malloc returns.

  • Related