Search code examples
carrayslistpointersrealloc

Passing list to a function to fill the list with variable number of members in C


I have written code to generate a list of (x, y, z) coordinates of a given length. The code functions if I generate this list in a main function, but passing a pointer to the list into a fill_xyz_list function produces a runtime error. Presumably there is an issue with dynamic memory allocation or pointers, but I can't find it!

What is the correct way to do this?

Background: I am trying to generate a walk cycle trajectory for a robotic leg, consisting of a finite list of (x, y, z) coordinates. As the trajectory resolution is dynamic, the list is of unknown length.

The following code produces a runtime error:

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

// core data structure
struct Point
{
    float x;
    float y;
    float z;
};

// function that allocates space for our array and fills it with dummy values
void fill_xyz_list(struct Point **xyz_list_ptr, int list_size)
{
    // allocate memory for 100 Point structs
    *xyz_list_ptr = realloc(*xyz_list_ptr, sizeof(struct Point)*list_size);

    // set values for each member
    int i;
    for (i=0; i<list_size; i++)
    {
        xyz_list_ptr[i]->x = i + 0.1;
        xyz_list_ptr[i]->y = i + 0.2;
        xyz_list_ptr[i]->z = i + 0.3;
    }
}

int main()
{
    struct Point *xyz_list = NULL; // our array of (x, y, z)
    int list_size; // our array size
    int i;

    // set list size
    list_size = 10;

    // fill xyz_list array with dummy values
    fill_xyz_list(&xyz_list, list_size);

    // print all members
    for (i=0; i<list_size; i++)
    {
        printf("xyz_list[%d]: x=%.2f, y=%.2f, z=%.2f\n", i, xyz_list[i].x, xyz_list[i].y, xyz_list[i].z);
    }

    return 0;
}

Solution

  • This line

    xyz_list_ptr[i]->x = i + 0.1;
    

    should be

    (*xyz_list_ptr)[i].x = i + 0.1;
    

    Otherwise you are interpreting xyz_list_ptr as an array of pointers instead of interpreting it as a pointer to an array, which it really is.

    Demo.

    Note: Assigning realloc back to the pointer being reallocated could lead to memory leaks. You should assign it to a temporary, check it for NULL, and only then assign the temporary to the original pointer:

    struct Point *tmp = realloc(*xyz_list_ptr, sizeof(struct Point)*list_size);
    if (!tmp) {
        ... // deal with allocation failure
        ... // exit the function
    }
    *xyz_list_ptr = tmp;