What is the correct usage of realloc() when it fails and returns NULL?
Asked Answered
N

4

17

Can anyone summarize what is the correct usage of realloc()?

What do you do when realloc() fails?

From what I have seen so far, it seems that if realloc() fails, you have to free() old pointer. Is that true?

Here is an example:

   1.  char *ptr = malloc(sizeof(*ptr) * 50);
   2.  ...
   3.  char *new_ptr = realloc(ptr, sizeof(*new_ptr) * 60);
   4.  if (!new_ptr) {
   5.      free(ptr);
   6.      return NULL;
   7.  }

Suppose realloc() fails on line 3. Am I doing the right thing on line 5 by free()ing ptr?

Natator answered 25/7, 2010 at 22:8 Comment(2)
What you have there looks good, as long as you have checked that the original malloc was successful.Anemometer
Actually, even if the original malloc() fails, realloc() is OK with a null pointer for its first argument - it then behaves like malloc(), and will (in this context) presumably fail too (because if malloc() cannot allocate 50 bytes, realloc() probably can't allocate 60 either).Prorate
C
22

From http://www.c-faq.com/malloc/realloc.html

If realloc cannot find enough space at all, it returns a null pointer, and leaves the previous region allocated.

Therefore you would indeed need to free the previously allocated memory still.

Croup answered 25/7, 2010 at 22:13 Comment(0)
P
1

It depends on what you want to do. When realloc fails, what is it you want to do: free the old block or keep it alive and unchanged? If you want to free it, then free it.

Keep in mind also, that in C89/90 if you make a realloc request with zero target size, realloc function may return a null pointer even though the original memory was successfully deallocated. This was a defect in C89/90, since there was no way to tell the success from failure on null return.

In C99 this defect was fixed and the strict relationship between null return and success/failure of reallocation was guaranteed. In C99 null return always means total failure of realloc.

Piscatorial answered 25/7, 2010 at 22:19 Comment(25)
As far as I can tell this is just wrong. C99 does not guarantee non-null return when the target size is 0; it allows either behavior. And aside from some GNU zealots, most people seem to consider the return 0 behavior to be the better choice. Moreover if the target size is 0, realloc cannot fail, so there's no need to check for failure.Factfinding
@R..: No, it isn't. You simply misunderstood the point. It is true that in C99 realloc with 0 size can return null or non-null, however in C99 the relationships "null means failure" and "non-null means success" was made strict. I.e. if realloc returns null in C99, the original memory is guaranteed to be not deallocated. In C89/90 this relationship was not strict: if you called realloc with 0 size and got null result, you con't tell whether the memory was deallocated or not.Piscatorial
@R..: And your last remark about "realloc cannot fail" is incorrect. The language specification does not guarantee (and never did) that realloc with zero size cannot fail. It can.Piscatorial
OK, I was reading the POSIX version of the documentation, which has the added sentence: "If size is 0 and ptr is not a null pointer, the object pointed to is freed." Contrary to policy, POSIX failed to mark this sentence "CX". Further reading in other sources suggests that C89 had the correct requirement that realloc with target size 0 act as free, and C99 broke it. Any real worthwhile implementation will follow POSIX anyway, at least...Factfinding
I can find no such requirement you claim exists. Can you provide a citation?Factfinding
@R..: realloc cannot act as free, because realloc has to return something and even C89/90 allowed non-zero returns. Which is the reason why in reality realloc with 0 size always acted as free followed by malloc(0). The C89/90 simply failed to describe this behavior properly and, for that reason probably, failed to provide a reliable failure detection method.Piscatorial
@R..: "I can find no such requirement you claim exists" - what specifically are you talking about?Piscatorial
POSIX requires realloc with target size 0 to act as free, so it most certainly can. See opengroup.org/onlinepubs/9699919799/functions/realloc.htmlFactfinding
The supposed requirement that realloc can only return 0 if the original object is not deallocated.Factfinding
@R..: Requires? You got it backwards. POSIX cannot require anything from C language. At the same time POSIX is allowed to require anything for itself as long as it fits into the constraints defined by C language specification. "Acting as free" does fit into these contraints, so that's perfectly fine. So, what are you trying to say? That it acts like free in POSIX? Great. But the topic is C in general, not POSIX.Piscatorial
@R..: The requirement "null return means failure" is explicitly stated in C99. Also, you might want to take a look at the "Rationale for C99" (open-std.org/jtc1/sc22/wg14/www/C99RationaleV5.10.pdf), where they explain why the specification of realloc was so changed: to allow for implementations that want to return non-null zero-size allocation requests. Apparently, such implementations exist.Piscatorial
@R..: a citation from your link is "Any conflict between the requirements described here and the ISO C standard is unintentional."Arsenite
Any implementation of realloc on a POSIX system must conform to the POSIX requirement. Of course that doesn't mean other C implementations have to do the same, but unless POSIX has a huge defect, it makes it very clear that realloc acting as free when the target size is 0 is one possible (not to mention the most likely) implementation behavior.Factfinding
POSIX also explicitly "requires" that fwrite is a binary I/O function. Can POSIX "require" that? Yes, for POSIX. Nevertheless fwrite is generally not a binary I/O function in C language.Piscatorial
@R..: By doing this, POSIX effectively outlaws implementations that want to "reserve" non-null pointers for zero-sized allocation requests. Can POSIX do that? Yes, it can. "Offending" implementations simply will not be POSIX. However, the C language does not want to outlaw such implementations. Hence the more intricate specification of realloc.Piscatorial
I've lost track of the point you're trying to make. 7.20.3.4 in the Rationale clearly says that target size 0 frees the object and that in this case, realloc may return 0. Your claim that a return value of 0 implies that the original object was not deallocated is simply false.Factfinding
The point I'm trying to make is that the OP's code is perfectly good for C99, but might theoretically be invalid for C89/90, even though it would require a maliciously illogical C89/90 implementation.Piscatorial
@R..: I understand what you are referring to in the Rationale, but the seems to be either a defect or poor wording in the Rationale. The intent of C99 is very explicit and clear: when realloc returns null pointer it is always an indication of failure, and that means that the old memory is not deallocated. This has been explained and clarified by the Committee many times already.Piscatorial
You're simply wrong. C99 makes no such requirement and you have failed to provide any evidence that it does. I have provided ample evidence that implementations can and do return 0 in the case of non-failure.Factfinding
@R..: No, I'm absolutely right and the wording in C99 is very explicit and clear. The text of C99 is all the evidence one needs. You provided no evidence whatsoever besides the reference to Rationale (which I, ironically, mentioned first). In any case, regardless of the amount of "evidence" one provides, until one manages to "overthrow" C99, that "evidence" has no weight. The only thing you provided in "ample" amounts is references to POSIX, which is laughably irrelevant in this case.Piscatorial
Show your citation please, kind sir. So far all you've done is show an affinity for the non-zero-return behavior glibc loves so much and everyone else seems to hate.Factfinding
In S 7.20.3 (pg 313), the C99 standard talks about memory management functions. It says, "If the size of the space requested is zero, the behavior is implementation defined: either a null pointer is returned, or the behavior is as if the size were some nonzero value, except that the returned pointer shall not be used to access an object." This is from the TC3 draft (I don't have the final version, but I can't imagine there'd be a difference).Hochheimer
Does a mod have to delete a comment section? Take it down a notch in here, I'm trying to sleep FFS.Sydel
@Dean Harding: There's no argument about the legality of null return. The question is about the post-conditions in the situation when a null pointer is returned. Is the old memory deallocated or not in that case?Piscatorial
@AudreyT: Ah, I see, well I can't answer that question :)Hochheimer
W
0

If realloc fails I don't think you would want to delete the original block since you will lose it. It seems like realloc will resize the old block (or return a pointer to a new location) and on success will return a pointer to the old block (or new location) and on failure will return NULL. If it couldn't allocate a new block the old block is untouched.

Wabash answered 25/7, 2010 at 22:25 Comment(0)
F
-4

Edit: Correction, some people are bashing me for what I said, the way you allocated your pointer seems to be best practice among them, I was taught to always go with type casts in the sizeof(), but apparently your way is more correct, so disregard what I said =)

Taking a peek at http://en.wikipedia.org/wiki/Malloc#realloc before might have done you some good.

You don't quite understand sizeof() - it has the value of the size of the argument you pass to it in bytes. For example, sizeof(int) will be 4 on most 32 bit systems but you should still use sizeof(int) instead of 4 because compiling your code on a 64 bit system (just as an example) will make that value equal to 8 and your code will still compile fine. What are you allocating memory for? Pointers? If so you should use sizeof(void*) instead (you can say sizeof(int*) but it's common convention not to mention to the compiler what you want to store at those pointers, since all pointers should be the same size - so most programmers say sizeof(void*)), if you need space for characters use sizeof(char) and so on.

You are however right to store the return value of realloc() in a new pointer and check it, though a lot of programmers will assume the system always has enough memory and get away with it.

Fortenberry answered 25/7, 2010 at 22:21 Comment(3)
His use of sizeof is perfectly fine and correct. sizeof(*ptr) is the size of the thing pointed to by ptr, so ptr = malloc(sizeof(*ptr) * N); is correct and idiomatic (although personally I would write it as ptr = malloc(N * sizeof ptr[0]);, but that is just style)Wattage
Quite the opposite: the way the OP does in his code is exactly how it should be done. Memory allocation requests should be made as type-independent as possible: no cast on the result of memory allocation function and no type names under the sizeof. The strange habit of using type names under sizeof in malloc requests (and such) has long ago earned its place in the garbage bin of C programming. Type names belong in declarations. If it is not a declaration, type names are not allowed (as much as possible).Piscatorial
foo = malloc(count * sizeof *foo); is a standard idiom for making sure you get the right size. You're treating the author of the question like he knows nothing about C while missing something pretty fundamental yourself..Factfinding

© 2022 - 2024 — McMap. All rights reserved.