2

I have a question, in my set-up I have variables like this:

bool** array_2d_bool;
char** array_2d_char;

...

So, for deallocating memory, I have the following:

void free_bool(bool** mat, int m)
{
    int i;
    for (i = 0; i < m; i++)
    {
        free(mat[i]);
    }
    free(mat);
}

However, I have to write a function for every type of 2D or 3D array I want to deallocate. Is there a way to write a function like this one?:

void deallocate_2d(void**, int m)

So that I can just use one function for deallocating any 2D array...

dpalma
  • 500
  • 5
  • 20

3 Answers3

2
bool** array_2d_bool;
char** array_2d_char;

These are not 2D arrays and cannot be used at pointing at 2D arrays. At best they can be used to point at the first element of an array of pointers.

And the only reason why you would want to use an array of pointers is when you want a lookup table, where each pointed-at type has different length, such as a string lookup table or a chained hash table. This isn't the case here, you just want a 2D array.

Using pointer-to-pointer for allocating a 2D array dynamically is always wrong, for multiple reasons: it doesn't create an actual array (so you can't use memcpy() and similar on it), it involves complex allocation/freeing that potentially leads to leaks, it causes heap segmentation and slower allocation, it gives poor cache performance and so on.

Instead allocate a 2D array:

malloc( sizeof(bool[x][y] );

Then point at it with an array pointer.

bool (*array_2d_bool)[x][y] = malloc( sizeof(bool[x][y] );

For ease of use, it is however much more convenient to point at the first array in this array of arrays, rather than pointing at the whole 2D array. So change it to this:

bool (*array_2d_bool)[y] = malloc( sizeof(bool[x][y] );

Now you can use it as array_2d_bool[i][j].

And when you are done, free it:

free(array_2d_bool);
Lundin
  • 195,001
  • 40
  • 254
  • 396
  • I was used to what some answers in here gave, for "allocating memory for a 2d array": http://stackoverflow.com/questions/17134650/how-to-allocate-memory-dynamically-for-a-two-dimensional-array. Does it mean, if I wanted to create a matrix of mxn, it is a bad idea doing it by using a double pointer and then allocate memory for each pointer? – dpalma Apr 19 '16 at 20:13
  • @dpalma Those answers weren't very good, there are far better answers in the [canonical duplicate](http://stackoverflow.com/questions/12462615/how-do-i-correctly-set-up-access-and-free-a-multidimensional-array-in-c). As I wrote in this answer, the only reason why you would want to use double pointer (pointer to 1st item in array of pointers) is because you need the individual items to have different lengths in relation to each other. Most obvious example, an array of pointers to char (strings). That is not a 2D array though. – Lundin Apr 19 '16 at 21:47
  • Another question... I think I did not understand really well, if I want to create a 2d array of size defined at run time (m and n are just for testing purposes), if I do this: http://pastebin.com/ECxF4F77 I get a seg fault... So, what is the problem there? – dpalma Apr 22 '16 at 16:34
0

You don't have nD-arrays. Pointers are no arrays. They also have different semantics.

Using a true nD-array makes deallocation straight forward:

#define INNER 10
#define OUTER 20

int (*arr)[INNER] = malloc(sizeof(*arr) * OUTER);

...

free(arr);

Except for the declaration, this is straight forward for more dimensions. freeing is even the same. No need for a seperate deallocation function.

too honest for this site
  • 12,050
  • 4
  • 30
  • 52
0

In computational science, it is pretty much standard for you to malloc() a 1D “array” (i.e. for an m by n matrix of doubles, do a single double *a=malloc(m*n*sizeof(double))), then do the index computation yourself, i.e. to get the element at i,j stored in a, you use a[i*n+j]. This has several advantages, including that it obviates the need to do multiple/nested malloc()s and free()s, adds very little in the way of cognitive overhead for the programmer, particularly since you can abstract the index computation away in a little inline function or a macro, and is readily extensible to higher dimensions.

A more detailed explanation can be found in this answer.

Community
  • 1
  • 1
Emmet
  • 6,192
  • 26
  • 39
  • 1
    This technique is outdated since the year 1999. There are VLAs now, and more importantly, pointers to VLAs. There is no need for "mangled" 2D arrays. And even before C99 you could use array pointers with fixed dimensions. – Lundin Apr 19 '16 at 06:33
  • There is no need for nested `malloc`/`free` if using a nD array. You compare apples (arrays/pointers to array) with oranges (pointers to pointers). Doing the index-calculation by hand is clumsy and error-prone. – too honest for this site Apr 19 '16 at 14:11
  • @Lundin As I understand it 1) VLAs are optional in C11, and 2) most implementations use stack for VLAs, which makes them pretty useless for even modestly sized matrices. – Emmet May 11 '16 at 21:56
  • @Olaf I disagree that doing index calculation by hand is clumsy and error-prone. If you want to do standard indexing only, it is easily encapsulated in an inline function that is no more clumsy and error-prone to use than native indexing. If you want to do, or anticipate that you might in future want to try, non-standard indexing (e.g. Morton indexing), it is at least possible. – Emmet May 11 '16 at 22:01
  • @Emmet: And using a function to do something the language already provides is not? Note that you always have to pass four arguments to that function: the array, two indexes and at least the inner dimension. Yeah, that is not clumsy... Re VLAs: Please read the standard before talking about something it does not even mention. The C standard does not even enforce a specific memory scheme for objects, thus there is no relateion to a "stack" with VLAs or any other type. And yes, you very well can use a pointer to a VLA, thus use a true 2D array with natural indexing. – too honest for this site May 11 '16 at 23:20
  • @Emmet ... The only point you have is they made it the optional with C11 for some hard to understand and often criticised reasons. However, any modern compiler which supports C99 provides them also in C11 mode (and no, MSVC is **not** a modern C compiler - it does not support standard C at all). – too honest for this site May 11 '16 at 23:21
  • @Olaf: The standard may be silent on the implementation issue, but the pragmatic reality is that most widely-used compilers implement VLAs with stack, which effectively disqualifies VLAs from being considered for even modestly large matrices. Nobody passes matrix dimensions in separate arguments (other than when using an API that offers no choice): that's what `struct`s are for. If you need to use column-major order or use non-linear indexing schemes, you simply change the index function rather than every occurrence of native indexing. Zero cost flexibility through encapsulation is a win. – Emmet May 12 '16 at 05:06
  • @Emmet VLAs will be available on every useful compiler. In this case you should be using a _pointer to VLA_ and not an actual VLA, see my answer. – Lundin May 12 '16 at 06:22
  • @Emmet: Any compiler which limits the use of VLAs is non-standard anyway. Please state **one** such compiler with a reference! gcc does not, nor does clang. – too honest for this site May 12 '16 at 11:18
  • @Olaf: OK. Suppose `ssz` is the stack size limit (from `getrlimit()`). With gcc 4.8.4 and icc 15.02, using a (`char`) VLA `vla[ssz]` reliably causes a segfault, while using `vla[ssz-10000]` reliably succeeds. If you're going to use a pointer to a VLA with `malloc()`, the only “advantage” is being able to write `A[i][j][k]` instead of (e.g.) `elt(A, i,j,k)`, but at the cost of shackling yourself to the built-in layout and indexing. You are entitled to take the view that this is a good trade-off. I take the view that it is not. – Emmet May 16 '16 at 21:38
  • No one stated to allocate the VLA on the stack. Just use a pointer to a VLA an `malloc` that array dynamically. The C standard does not even require an implementation to sue a stack (or a heap or any other specific allocation scheme). – too honest for this site May 16 '16 at 23:27
  • @Olaf: the C standard does not require an implementation to have VLAs *AT ALL*. If you want to use an optional feature, be shackled to the built-in layout, linear indexing, and worry about past/future compiler support, that is your prerogative. Personally, I'll stick with the de facto standard, time-tested scheme that is guaranteed to work with old/new compilers, enables trivial switching between column- and row-major linear indexing, and preserves the ability to use non-linear indexing merely by writing the appropriate function/macro. – Emmet May 17 '16 at 00:33