-5

I am wondering what is the best way to clean up memory which was already allocated during the failed creation of 2D array.

int** a = (int**)malloc(rows * sizeof(int*));
for (int i = 0; i != rows; ++i)
    a[i] = (int*)malloc(columns * sizeof(int));

for (int i = 0; i != rows; ++i)
    free(a[i]);

free(a);

The sample code above should work like a charm. However malloc can return null and when it will the code above will not handle the problem. How can we protect such case?

Let's say (int*)malloc(columns * sizeof(int)) returned null for i = 3. We already have allocated space for int** a and a[0], a[1] and a[2].

Here is my current approach. Ugly and not sure if correct. This is why I am asking you for help.

int rows;
int columns;
scanf("%d", &rows);
scanf("%d", &columns);

int** a = (int**)malloc(rows * sizeof(int*));
if (!a)
{
    printf("Cannot allocate enough space."); // nothing to clean up here
    return 1; // to make example easier
}

int i;
bool arrayCreated = true;

for (i = 0; i != rows; ++i)
{
    int* tmp = (int*)malloc(columns * sizeof(int));
    if (!tmp) // malloc returned null
    {
        arrayCreated = false; // let's mark that we need to do some cleanup
        break;
    }
    a[i] = tmp;
}

if (!arrayCreated) // creation failed, clean up is needed
{
    for (int j = 0; j <= i; ++j)
        free(a[j]);
}
else
{
    for (int i = 0; i != rows; ++i)
        free(a[i]);
}

free(a);
dptd
  • 274
  • 1
  • 3
  • 12
  • @πάνταῥεῖ It would be great to see a full example. Do you mind sharing? – dptd May 23 '16 at 21:09
  • Lots of questions, better to post for one language at a time. – chux - Reinstate Monica May 23 '16 at 21:09
  • @ArchbishopOfBanterbury I love containers and smart pointers and I am using them all the time. I was just wondering how it was done in the past. – dptd May 23 '16 at 21:10
  • [Like This](http://ideone.com/I5283H) ? – Michi May 23 '16 at 21:18
  • Why is there a mixture of C++'s `delete` and C's `free`... ? *frowns* – t0mm13b May 23 '16 at 21:19
  • 2
    @dptd Don't mix `new`, `malloc` and `free`. That's a strong rule. – πάντα ῥεῖ May 23 '16 at 21:22
  • 1
    @dptd Also elaborate in your question please, why you think these comments and answers are actually ***useless***? These are the idiomatic ways to deal with memory allocation. I you want something different choose another programming language, – πάντα ῥεῖ May 23 '16 at 21:41
  • Your `calloc` allocations are `sizeof(int*)` times too large. – kfsone May 24 '16 at 00:01
  • @πάνταῥεῖ This answers are useless for me because I know how to work with containers and smart pointers. What I do not know is how to clean up memory when error occurs during dynamic allocation in the loop. I pointed it few times already but somehow people keep saying the same thing again and again. – dptd May 24 '16 at 04:16
  • Please write one question for c and one for c++ – MikeMB May 24 '16 at 06:19
  • @MikeMB I will when I will be able to. Currently I cannot ask new questions because this one has too many negative votes. – dptd May 24 '16 at 06:30

3 Answers3

2

In short:

As you have different functions used to allocate memory, you'll need to call their counterpart deallocation functions accordingly:

  • malloc(), calloc() and realloc() need to be deallocated with a call to free()
  • X* x = new X(); needs to be deallocated with delete x;
  • X** x = new X[10]; needs to be deallocated with delete[] x;

The idiomatic way in c++ is to use either a container

  • std::vector<X> x;

or a smart pointer like

  • std::unique_ptr<X> x = std::make_unique<X>();

to redeem you from caring about the necessary bookkeeping to balance allocation/deallocation operations correctly.


Please notice that this is a theoretical question about error handling in such, specific cases. I want to highlight that first two cases are for C, not C++.

There's no standard error handling defined if you're using the wrong pairs of dynamic memory de-/allocation functions.

As mentioned above they need to pair like described. Anything else calls undefined behavior.

πάντα ῥεῖ
  • 1
  • 13
  • 116
  • 190
1
int** b = (int**)calloc(sizeof(int*) * rows, sizeof(int*));

This is not correct, the first parameter of calloc is "number of elements to allocate".

should be

int** b = (int**)calloc(rows, sizeof(int*)); /* No need to cast in C */

What is the safe way for creating multidimensional arrays in C and C++ for such scenarios?

In C (in order to avoid segmentation) a real 2D dynamic array should be declared as

int (*arr)[columns]; /* A pointer to an array of n ints */

and (m)allocated using

arr = malloc(sizeof(int [rows][columns]));

or

arr = calloc(rows, sizeof(int[columns]));

In this way a single call to free(arr); is enough.

David Ranieri
  • 39,972
  • 7
  • 52
  • 94
  • **In C a real 2D array should be declared as...** You didn't explain why. – Michi May 23 '16 at 21:36
  • @Michi, the code provided by OP is a segmented pointer-to-pointer thing, this is explained in this thread: http://stackoverflow.com/questions/12462615/how-do-i-correctly-set-up-access-and-free-a-multidimensional-array-in-c – David Ranieri May 23 '16 at 21:46
  • 1
    I though that it will be good for the OP and new comers in/to **C** :) – Michi May 23 '16 at 21:52
  • @AlterMann In `int (*arr)[columns];` can `columns` value be provided during the runtime or maybe this value must be known at the compile time? – dptd May 24 '16 at 11:24
  • Yes, when provided at runtime it is called VLA [Variable length array](https://en.wikipedia.org/wiki/Variable-length_array) – David Ranieri May 24 '16 at 11:36
0

I'm not sure about C, but C++; delete[] should suffice.

sntnmjones
  • 15
  • 9