0

I've read this example for allocating an array of pointers, and allocating a contiguous block of memory as an alternative to a two dimensional array, allowing specifying both dimensions at run time: http://c-faq.com/aryptr/dynmuldimary.html

    int **array2 = malloc(nrows * sizeof(int *));
    array2[0] = malloc(nrows * ncolumns * sizeof(int));
    for(i = 1; i < nrows; i++)
        array2[i] = array2[0] + i * ncolumns;

With this approach you can also reference values with two sets of brackets as:

    array2[i][j]

In contrast, a single malloc() call could force you to compute an index value, and reference the array using on one set of brackets, like this:

    array2[i*ncolumns + j]

However, in order to properly free memory with the approach using two sets of brackets, you must do:

    free(array2[0]);
    free(array2);

Is it possible to do the approach of using two sets of brackets, have entirely contiguous memory, but do it all with only 1 malloc() call? (which goes hand in hand with contiguous memory).

And if so, then you would ideally be able to free memory with a single call:

    free(array2);

With the approach of calling malloc() twice, memory is not necessarily entirely contiguous. The buffer where all the data is ultimately stored is contiguous, but the array of pointers for retrieving each row can be located elsewhere in memory (since it is a separate malloc() call).

Can the entire allocated buffer start off at the address contained in array2, and then the data stored starting at the address in array2[0] begin offset from that by nrows * sizeof(int *)?

The C FAQ also lists an example:

    int (*array4)[NCOLUMNS] = malloc(nrows * sizeof(*array4));

However, this fixes one dimension at compile time. Is it possible for a single malloc() call, access using two sets of brackets, and specify both dimensions at run time?

Why will this fail, or what is wrong with this?

    int i;
    size_t sizeof_rows = nrows * sizeof(int *);
    size_t total = sizeof_rows + nrows * ncolumns * sizeof(int);
    int **array2 = malloc(total);
    array2[0] = (int *)(array2 + sizeof_rows);
    for (i = 1; i < nrows; i++)
        array2[i] = array2[0] + i * ncolumns;
Rich Jahn
  • 397
  • 3
  • 14
  • 1
    `int **array2` declares a pointer to a pointer. Neither this itself nor the thing to which it points is a two-dimensional array. – John Bollinger May 26 '16 at 21:11
  • there is no other way to declare or dynamically allocate a pointer to a 2D array. C does support variable-length arrays, however, and you can apply the linked answer to dynamically allocating an array with both dimensions determined a run time. This can be safer than a full 2D VLA because VLAs are typically allocated on the stack, and if you're not careful then you can easily run out of stack space. – John Bollinger May 26 '16 at 21:29
  • That makes sense. My understanding is VLA using stack space requires C99 though. I'm more curious why the two malloc() calls are necessary in the C FAQ example as opposed to a single malloc() call and additional pointer arithmetic. – Rich Jahn May 26 '16 at 21:35
  • More than two `malloc()` and two corresponding `free()` calls are ordinarily required for the pointer to pointer case. You allocate space for an array of pointers, and then allocate space for each pointer in that array. When you're done, each of those allocations must be freed separately. As for VLAs requiring C99, yes, they do. And the current standard is C2011, and even that is already 5 years old. – John Bollinger May 26 '16 at 22:05
  • I added a code snippet above at the end. Why will the approach of a single malloc fail, or what is wrong with it? – Rich Jahn May 26 '16 at 23:41
  • You could use pointer to pointer form in a way that that reserves space for all the pointers and all the ultimate values, all in one go, which seems to be what you're trying to do. Your example doesn't do this correctly, however, because it gets the pointer arithmetic wrong. In any case, this is inferior to using a *bona fide* pointer to array (type such as `(int (*)[n])`) because accessing the elements is more expensive. Additionally, this approach can run into trouble with optimizing compilers on account of violating the strict aliasing rule. – John Bollinger May 27 '16 at 13:01

0 Answers0