0

I am having some issues with two arrays in C. Specifically, I pass two arrays to a function, malloc them and fill them with data and when I try to use them in my main program I get a segmentation fault.

int readData(FILE *f, int * regionSize, float **regions)
{
    regionSize = (int *)calloc(10,sizeof(int));     

    // Fill regionSize

    regions = (float **)malloc(10*sizeof(float *));
    for(i=0;i<10;i++)
    {
        regions[i] = (float*)malloc(regionSize[i]*sizeof(float));
    }

    // Fill regions
    // Everything prints ok here
    return 0;
}


int main(int argc, char **argv)
{

    int *regionSize;
    float **regions;
    readData(f,regionSize, regions);

    printf("print------------------------\n");

    for(i=0;i<10;i++)
    {
        for(j=0;j<userRegionsSize[i];j+=4)   //  SEGMENTATION FAULT HERE
        {
            //print
        }
    }
}


What am I missing?

caspar
  • 13
  • 6
  • 2
    C doesn't have reference arguments, but they can be emulated by passing *pointers* to the variables (using the pointer-to operator `&`). – Some programmer dude Mar 14 '22 at 18:39
  • 1
    Also, in C [you don't have to (and really shouldn't) cast the result of `malloc` (or other functions returning `void *`)](https://stackoverflow.com/questions/605845/do-i-cast-the-result-of-malloc). – Some programmer dude Mar 14 '22 at 18:40
  • 1
    C is pass-by-_value_, so a _copy_ of `regions` is made when you pass it to `readData`. Any assignment to it (eg `regions = ...`) is lost when the function returns. You either need to return a value from `readData`, or pass a pointer to the argument, and dereference and assign in the function. – yano Mar 14 '22 at 18:42
  • Also note the `// Fill regions` comment, all elements of `regionSize` are 0, so you're not `malloc`ing any space for `regions[i]` anyway. – yano Mar 14 '22 at 18:46
  • @yano you are not correct. I put the ` // Fill regionSize` and `// Fill regions ` comments there to show you that I am actually mallocing space but omitted the code for simplicity. – caspar Mar 14 '22 at 18:51
  • Please note that @yano is correct. The comment may need elaboration, Please see my answer below – Sebastian Cabot Mar 14 '22 at 19:09
  • 1
    Ok my mistake, I interpreted that comment as a "TODO" instead of "already have done". Note that it's best to post a [mre] to eliminate the possibility for such things. – yano Mar 14 '22 at 19:16

1 Answers1

2

You have a common mistake shared with many new C programmers. When you pass a pointer to a function you are copying the address held in that pointer to the argument variable. So now both the original parameter and the argument variable point to the same place.

Consider this code

int *x = malloc(sizeof(int)); // x holds the address of the newly allocated memory
*x = 5; // The memory pointed by x now has the value 5
int *y = x; // y points to the same address x points to
y = malloc(sizeof(int)); // y points to a new address in memory - note x is unchanged

What you see in the last line of code is essentially what happens when you allocate a pointer the way you did in your function - the original pointer didn't change.

To actually change the value the original pointer points to you have to pass the address of that pointer variable.

See this code

void allocate_pointers(int **array_of_ints, int ***array_of_array_of_ints)
{
    int i, j;
    *array_of_ints = malloc(10*sizeof(int));
    *array_of_array_of_ints = malloc(10*sizeof(int*)); // Note the allocation of pointers here (not int)

    for(i = 0; i < 10; ++i) {
        (*array_of_ints)[i] = i;
        (*array_of_array_of_ints)[i] = malloc(10*sizeof(int));
        for(j = 0; j < 10; ++j)
            (*array_of_array_of_ints)[i][j] = j;
    }
}

int main(int argc, const char**argv)
{
    int *array_of_ints;
    int **array_of_array_of_ints;
    allocate_pointer(&array_of_ints, &array_of_array_of_ints);

    return 0;
}
Sebastian Cabot
  • 1,812
  • 14
  • 18