6

This is the way I've been taught to use realloc():

int *a = malloc(10);
a = realloc(a, 100); // Why do we do "a = .... ?"
if(a == NULL) 
//Deal with problem.....

Isn't that redundant? Can't i just do something like this? :

if(realloc(a, 100) == NULL) //Deal with the problem

Same for other realloc examples i've found around, for example:

int *oldPtr = malloc(10);
int * newPtr = realloc(oldPtr, 100);
if(newPtr == NULL) //deal with problems
else oldPtr = newPtr;

Can't i just do this instead? :

int *oldPtr = malloc(10);
if(realloc(oldPtr, 100) == NULL)  //deal with problems
//else not necessary, oldPtr has already been reallocated and has now 100 elements
Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335
Sir_Playsalot
  • 61
  • 1
  • 3
  • 10
    It’s not redundant. `realloc` might return a different pointer and invalidate the old one. Read [`man realloc`](https://linux.die.net/man/3/realloc). – Ry- Jun 27 '17 at 20:29
  • 1
    @Ryan: OTOH, the way the OP has been taught is *also* bad, since it leaks the original allocation if `realloc()` fails. – EOF Jun 27 '17 at 20:33
  • 1
    Realloc returns a pointer. You have to collect it somewhere. – Pushan Gupta Jun 27 '17 at 20:37
  • Corner consideration: If the new size is 0, special considerations are needed as as the return value from `realloc(...., 0)` is not necessarily an out-of-memory. `realloc(...., more_than_zero)` returns `NULL` on out-of-memory and also may/may not return a non-out-of-memory `NULL` on `realloc(...., 0)`. – chux - Reinstate Monica Jun 27 '17 at 21:17
  • 1
    This is not redundant. There is no guarantee that realloc() will return the same address. – LinuxStuff Jun 28 '17 at 05:39

4 Answers4

11

realloc returns a pointer to the resized buffer; this pointer value may be different from the original pointer value, so you need to save that return value somewhere.

realloc may return NULL if the request cannot be satsified (in which case the original buffer is left in place). For that reason, you want to save the return value to a different pointer variable than the original. Otherwise, you risk overwriting your original pointer with NULL and losing your only reference to that buffer.

Example:

size_t buf_size = 0; // keep track of our buffer size

// ...

int *a = malloc(sizeof *a * some_size); // initial allocation
if (a)
    buf_size = some_size;

// ...

int *tmp = realloc(a, sizeof *a * new_size); // reallocation
if (tmp) {
    a = tmp;             // save new pointer value
    buf_size = new_size; // and new buffer size
}
else {
    // realloc failure, handle as appropriate
}
Swordfish
  • 12,971
  • 3
  • 21
  • 43
John Bode
  • 119,563
  • 19
  • 122
  • 198
  • [Actually, if `new_size` is zero, return-value `NULL` does not consistently mean error.](https://en.cppreference.com/w/c/memory/realloc) – Deduplicator May 14 '19 at 00:49
4

the correct way to call realloc is to save the return value in a temporary variable and check it for NULL. That way if realloc has failed, you haven't lost your original memory. For example:

int *a, *b;
a = malloc(10); 
b = realloc(a, 100);
if (b == NULL) {
    // handle error and exit
}
a = b;

EDIT: Note that if the error handling doesn't exit, you should put the last line above, i.e. a = b; inside an else clause.

bruceg
  • 2,433
  • 1
  • 22
  • 29
  • You most likely wouldn't continue on the standard flow of execution in the function if memory allocation failed. The error handling should exit. If somehow you can handle the error and continue, definitely should be in an else. – bruceg Jun 27 '17 at 21:08
3

realloc on failure keeps the original pointer and size. realloc on success may not (and often does not) return the exact same pointer as the input.

So the proper solution is your third example.

int *oldPtr = malloc(10);
int * newPtr = realloc(oldPtr, 100);
if(newPtr == NULL) //deal with problems
else oldPtr = newPtr;
  • I am looking for clarity. If realloc does not return the exact same pointer, don't we encounter memory leaks? Doesn't the following code cause leaks: int *oldPtr = malloc(10); int *newPtr = malloc(100); oldPtr = newPtr; //we no longer have reference to the first malloc, hence cannot free it. – Prox Jun 26 '20 at 19:43
  • I got my answer, realloc frees the old memory on success, https://stackoverflow.com/a/34615642/7802476. Does that mean if you use the old pointer after realloc (without the else statement) you get undefined behavior? – Prox Jun 26 '20 at 19:55
2

This code snippet is wrong.

int *a = malloc(10);
a = realloc(a, 100); // Why do we do "a = .... ?"
if(a == NULL) 
//Deal with problem.....

If the call of realloc returns NULL then the previous value of the pointer a is lost. So there can be a memory leak because it will be impossible to free the memory allocated by the call of malloc.

If just to write

if(realloc(a, 100) == NULL) //Deal with the problem

then in turn the returned pointer of the call of the realloc can be lost.

This code snippet

int *oldPtr = malloc(10);
int * newPtr = realloc(oldPtr, 100);
if(newPtr == NULL) //deal with problems
else oldPtr = newPtr;

is correct. However if to write

int *oldPtr = malloc(10);
if(realloc(oldPtr, 100) == NULL)  //deal with problems
//else not necessary, oldPtr has already been reallocated and has now 100 elements

then again the returned pointer of the call of realloc can be lost.

From the description of realloc in the C Standard (7.22.3.5 The realloc function)

4 The realloc function returns a pointer to the new object (which may have (or may not have - added by me) the same value as a pointer to the old object, or a null pointer if the new object could not be allocated.

Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335