~skeeto/public-inbox

Legitimate Use of Variable Length Arrays

Brett Kuntz
Details
Message ID
<223994466.443623753.1590450353746.JavaMail.zimbra@shaw.ca>
DKIM signature
pass
Download raw message
Hello, I see you have stumbled into the wonderful world of multi-dimensional pointers. I have used and abused them for years and I have some additional tips for you!

Generally speaking, avoid using the pointer * symbol always. An exception is if a pointer points to a single item, like a structure. Use the square brackets everywhere else, it is cleaner to read, and there is a much lower chance a person messes up pointer arithmetic.

These 4 functions are equivalent, some "look nicer" than others. sum3b and sum3d are my go-to's in a situation like this.

int sum3(int (*array)[3])
{
    return (*array)[0] + (*array)[1] + (*array)[2];
}

int sum3b(int (*array)[3])
{
    return array[0][0] + array[0][1] + array[0][2];
}

int sum3c(int *array)
{
    return array[0] + array[1] + array[2];
}

int sum3d(int (*array)[3])
{
    int *a = (int*)array;
    return a[0] + a[1] + a[2];
}

Here are 16 ways to use them:

int buff[] = { 1, 2, 4 };

printf("r = %d\n", sum3(&buff));
printf("r = %d\n", sum3b(&buff));
printf("r = %d\n", sum3c(buff));
printf("r = %d\n", sum3d(&buff));

int buff2[][3] = { { 1, 2, 4 } };

printf("r = %d\n", sum3(buff2));
printf("r = %d\n", sum3b(buff2));
printf("r = %d\n", sum3c(buff2[0]));
printf("r = %d\n", sum3d(buff2));

int buff[3] = { 1, 2, 4 };

printf("r = %d\n", sum3(&buff));
printf("r = %d\n", sum3b(&buff));
printf("r = %d\n", sum3c(buff));
printf("r = %d\n", sum3d(&buff));

int buff2[1][3] = { { 1, 2, 4 } };

printf("r = %d\n", sum3(buff2));
printf("r = %d\n", sum3b(buff2));
printf("r = %d\n", sum3c(buff2[0]));
printf("r = %d\n", sum3d(buff2));

Here's another way to write one of your examples:

int array[][3] = malloc(sizeof(int) * 3);
array[0][0] = 1;
array[0][1] = 2;
array[0][2] = 4;
int r = sum3(array);
free(array);

Another example:

int n = /* run-time value */;
/* TODO: Check for integer overflow. See note. */
float identity[][n][n] = malloc(sizeof(float) * n * n);
if (identity) {
    for (int y = 0; y < n; y++) {
        for (int x = 0; x < n; x++) {
            identity[0][y][x] = x == y;
        }
    }
}

And finally, here is my favourite method that I use very often, it is pretty close to "bru del"'s method. Notice how smooth and clean it is! Notice how we can use the [y] offset, we can do this since the size of all of the remaining dimensions is known by the compiler. This works up to as many dimensions as possible.

float identity[][n] = malloc(sizeof(float) * n * n);
if (identity) {
    for (int y = 0; y < n; y++) {
        for (int x = 0; x < n; x++) {
            identity[y][x] = x == y;
        }
    }
}

If we wanted to make a 3D Cube of the above code:

float identity[][n][n] = malloc(sizeof(float) * n * n * n);
if (identity) {
    for (int z = 0; z < n; z++) {
        for (int y = 0; y < n; y++) {
            for (int x = 0; x < n; x++) {
                identity[z][y][x] = 12345;
            }
        }
    }
}

Hope this helps!

-Brett Kuntz
Export thread (mbox)