tags:

views:

275

answers:

4

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?

Thanks, Boda Cydo.

+5  A: 

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.

Gian
+1  A: 

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.

AndreyT
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.
R..
@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.
AndreyT
@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.
AndreyT
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...
R..
I can find no such requirement you claim exists. Can you provide a citation?
R..
@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.
AndreyT
@R..: "I can find no such requirement you claim exists" - what specifically are you talking about?
AndreyT
POSIX **requires** `realloc` with target size 0 to act as `free`, so it most certainly can. See http://www.opengroup.org/onlinepubs/9699919799/functions/realloc.html
R..
The supposed requirement that `realloc` can only return 0 if the original object is not deallocated.
R..
@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.
AndreyT
@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" (http://www.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.
AndreyT
@R..: a citation from your link is *"Any conflict between the requirements described here and the ISO C standard is unintentional."*
kaizer.se
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.
R..
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.
AndreyT
@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`.
AndreyT
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.
R..
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.
AndreyT
@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.
AndreyT
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.
R..
@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.
AndreyT
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.
R..
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).
Dean Harding
Does a mod have to delete a comment section? Take it down a notch in here, I'm trying to sleep FFS.
Will
@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?
AndreyT
@AudreyT: Ah, I see, well I can't answer that question :)
Dean Harding
A: 

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.

btfx
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)
caf
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).
AndreyT
`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..
R..
A: 

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.

Cervo