Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Allocating several arrays of the same type

Tags:

arrays

c

malloc

I need to allocate several arrays of the same type and shape. At the beginning, I did something like:

void alloc_arrays_v1(size_t nmemb)
{
    int *a1, *a2, *a3;

    a1 = malloc(nmemb * sizeof int);
    a2 = malloc(nmemb * sizeof int);
    a3 = malloc(nmemb * sizeof int);

    /* do some stuff with the arrays */

    free(a1);
    free(a2);
    free(a3);
}

To avoid calling malloc and free several times, I changed the above into:

void alloc_arrays_v2(size_t nmemb)
{
    int *a, *a1, *a2, *a3;

    a = malloc(3 * nmemb * sizeof int);
    a1 = a;
    a2 = a1 + nmemb;
    a3 = a2 + nmemb;

    /* do some stuff */

    free(a);
}

This seems to be ok (in the sense that the functions behave the same way in the real-world case), but I wonder if this is still valid C code (undefined behaviour?), and if I can extend this method to complex data kind (arrays of structs, etc.).

like image 402
michaelmeyer Avatar asked Jan 31 '14 08:01

michaelmeyer


Video Answer


3 Answers

It is entirely valid in C. But remember to free only the a pointer. Your this method is similar to struct hack

However I think one logical problem in this code is that if you go out of bounds for a1 or a2 you will not be able to notice it as you will be accessing valid memory addresses, i.e. you will not get Seg Fault.
However, in first case you "may" get SegFault and notice your error.

like image 93
Don't You Worry Child Avatar answered Oct 24 '22 03:10

Don't You Worry Child


Both are valid since you're using malloc to allocate contiguous memory. In fact code similar in form to the second case is often used when modelling matrices in C.

It's worth noting that

int a1, a2, a3, a4;
int* a = &a1;
int oops = *(a + 1);

is undefined behaviour, since you cannot expect the stack allocation to be contiguous.

like image 20
Bathsheba Avatar answered Oct 24 '22 05:10

Bathsheba


It is perfectly valid.

What you do is essentially the same as this:

void alloc_arrays_v1(size_t nmemb)
{
    typedef int one_array[nmemb]; // this is one array
    typedef one_array three_arrays[3]; // this are three arrays

    one_array * a;
    int *a1, *a2, *a3;
    a = malloc(sizeof(three_arrays));

    a1 = a[0]; // a[0] is a one_array, which decays into an int * here.
    a2 = a[1]; // the same
    a3 = a[2]; // as above

    /* do some stuff with the arrays */

    free(a);
}

with the difference that the calculations are done by pointer and array arithmetics here.

like image 22
glglgl Avatar answered Oct 24 '22 05:10

glglgl