0

I want to pass a structure pointer to a function that will dynamically create a array of structures at the location pointed to by the structure pointer that was passed. I am able to create and fill the array of structure successfully but when trying to print the data in the calling function using the pointer that was passed gives me a garbage values. Please help me know why my structure pointer is pointing to garbage and how can I access my data correctly.

The following is just some example code to demonstrate how the structure is passed and dynamically filled using malloc & realloc. this is INCORRECT method:

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

struct student 
{
    int id;
    char name[20];
    float percentage;
};

void func(struct student *record);

int main() 
{
    struct student *record = NULL;

    record = (struct student *)malloc(sizeof(struct student));

    func(record);

    if(record != NULL)
    {
        for(int i=0; i<2; i++)
        {
            printf(" 1 Id is: %d \n", record[i].id);
            printf(" 1 Name is: %s \n", record[i].name);
            printf(" 1 Percentage is: %f \n", record[i].percentage);
            printf("\n");
        }
    }
    else
    {
        printf("record pointer is null");
    }

    return 0;
}

void func(struct student *record1)
{
    for(int i=0; i<2; i++)
    {
        if(i)
        {
            record1 = (struct student *)realloc(record1,sizeof(struct student)*(i+1));
        }
        record1[i].id=1;
        strcpy(record1[i].name, "Raju");
        record1[i].percentage = 86.5;
    }
}

The following is a similar example using double pointer which is the CORRECT way to do this:

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

struct student 
{
    int id;
    char name[20];
    float percentage;
};

void func(struct student **record);

int main() 
{
    struct student *record = NULL;

    func(&record);

    if(record != NULL)
    {
        for(int i=0; i<2; i++)
        {
            printf(" 1 Id is: %d \n", record[i].id);
            printf(" 1 Name is: %s \n", record[i].name);
            printf(" 1 Percentage is: %f \n", record[i].percentage);
            printf("\n");
        }
    }
    else
    {
        printf("record pointer is null");
    }

    free(record);

    return 0;
}

void func(struct student **record1)
{
    *record1 = (struct student *)malloc(sizeof(struct student));
    for(int i=0; i<2; i++)
    {
        if(i)
        {
            *record1 = (struct student *)realloc(*record1,sizeof(struct student)*(i+1));
        }
        (*record1)[i].id=1;
        strcpy((*record1)[i].name, "Raju");
        (*record1)[i].percentage = 86.5;
    }
}
Ghos3t
  • 174
  • 1
  • 14
  • 4
    If you program in C++ why do you use `malloc` and `free` and `realloc`? The "correct" solution here is to use `std::vector`. – Some programmer dude Jan 16 '18 at 05:42
  • @Someprogrammerdude I am mostly trying for a C based solution but if needed I could also work with C++ concepts, I will look into vectors. – Ghos3t Jan 16 '18 at 06:11
  • @O'Neil Since there were a bunch of issues with the example I had posted I replaced it with to new simpler examples one of which is working. So since you mentioned that ap_test is a copy of my pointer test, then If I need it to point to the same location as the original pointer what should I do. I have tried using Double Pointer but I am getting Debug Assertion Failure message. Surprisingly in the new example I have provided it is working even with the copy of the pointer. – Ghos3t Jan 16 '18 at 06:16
  • 1
    `record1` => `*record1` within `realloc`. It's less error prone to use a temporary pointer to do all the stuff, and eventually assign `*record1 = that_pointer;`. About the surprising copy result, I guess realloc didn't change the adress while reallocating. – O'Neil Jan 16 '18 at 06:23
  • @O'Neil Your last suggestion worked for me, you should post this as a answer and I will mark it as accepted. Thank you. – Ghos3t Jan 16 '18 at 06:47
  • Additionally, don't cast `malloc` and `realloc` for no reason. `if(i)` when you are looping through `i` from `0` to `1`, and `realloc` only if `i` is not zero, there has to be a better and efficient way of doing it. – WedaPashi Jan 16 '18 at 06:58
  • 1
    @O'Neil make sure you explain in your write-up why passing `struct student *record` does not work. How the addresses for `record` are separate and distinct between `main` and `func` and why passing the *address of* `record` is required. – David C. Rankin Jan 16 '18 at 07:05

1 Answers1

1

Your first solution,

record1 = (struct student *)realloc(record1,sizeof(struct student)*(i+1));

works as long as realloc does not have to move the pointer! That is, realloc just expands the memory area it gave earlier to record1. Should, at some later stage, realloc be required to give you another piece of memory, then the earlier pointer record in main will become invalid and could now contain your "garbage".

As you were thinking, you need a double pointer to be able to see the changed pointer in main. You were nearly there, just a typo:

*record1 = (struct student *)realloc(record1,sizeof(struct student)*(i+1));

in the above line the second occurrence of record1 must also be dereferenced, so *record1 because you must give realloc the original pointer.

Oh, and don't cast the result of malloc! Although the compiler does not complain, it can cause future problems.

Paul Ogilvie
  • 25,048
  • 4
  • 23
  • 41
  • can you tell me why casting malloc is bad. Also when I try to remove the type cast in my second example and compile the code I get the error message: a value of type "void *" cannot be assigned to an entity of type "student *". So how do I avoid type casting the return value of malloc in my case. – Ghos3t Jan 16 '18 at 08:15
  • @Ghos3t: Thats a different question, and it already has a great answer. See [Do I cast the result of malloc?](https://stackoverflow.com/q/605845/4228131), and the accepted answer. – WedaPashi Jan 16 '18 at 08:48
  • 1
    Good reference from WedaPashi. But when your compiler complains about that void pointer, then you are compiling as C++, not as C. – Paul Ogilvie Jan 16 '18 at 09:40