开发者

malloc and realloc functions

开发者 https://www.devze.com 2023-03-15 16:19 出处:网络
int main( ) { int *p; p=(int *)malloc(20); printf(\"%u\",p); \\\\ printing some memory adress p=(int *)realloc(p,0);
int main( )    
{
    int *p;
    p=(int *)malloc(20);
    printf("%u",p); \\ printing some memory adress 
    p=(int *)realloc(p,0);
    printf("%u",p); \\ printing开发者_如何学JAVA as 0
    printf("%u",*p); \\ printing the value as 0
}

Now my question is the statement relloc working as the free() function as the pointer p is pointing to the NULL and NULL value in it. Will that 20 bytes be freed?


No, it may not be freed in all circumstances. C99 has this to say in 7.20.3.4 The realloc function:

If memory for the new object cannot be allocated, the old object is not deallocated and its value is unchanged.

Now you may think that an allocation of zero bytes couldn't possibly fail but the standard doesn't mandate that. It says, for zero-sized objects:

If the size of the space requested is zero, the behaviour is implementation defined: either a null pointer is returned, or the behaviour is as if the size were some non-zero value, except that the returned pointer shall not be used to access an object.

So, if your implementation is one of those that doesn't return NULL for a zero-size allocation, and it requires some housekeeping information for each allocation, and the memory arena is so full that you can't store even another housekeeping header, and it's not smart enough just to split the current allocation and return most of it to the arena, it may fail a zero-size realloc and hence not free the original memory.

Now this is a (very) edge case depending on a lot of decisions made in the implementation, most of which may seem bizarre to people with experience of writing them. Unfortunately, we have to allow for the edge cases as well :-)

If it really worries you, I'd just change:

p=(int *)realloc(p,0);

into:

free (p) ; p = NULL;

A couple of other points.

  1. Comment marjers are forward slashes /, not backslashes.
  2. You are not allowed to dereference p in that final line whether or not your implementation returns NULL for a zero-size allocation. See my second quote above where it states: "except that the returned pointer shall not be used to access an object".
  3. You shouldn't really cast the return values from malloc-type calls. This is a hangover from the dim dark past before C had a void*, and malloc returned char*. The problem with doing so nowadays is, if you forget to include stdlib.h, problems can be hidden from you.


If the size given to realloc is 0 together with an allocated pointer then it will free the memory the pointer points to and will return NULL.

Which brings the next question:

Why do you do this then:

printf("%u",*p); \\ printing the value as 0

p is NULL at this point, and you're still dereferencing it. What for? What do you expect to happen here?


First this is very platform dependent. Your realloc call definitely does not work as a free... using the pointer as you did would get some kind of segmentation fault or crash if it did set p to the NULL pointer...

Whether the realloc will "free" the 20 bytes or not (again) completely depends on the OS / library implementing that realloc.

EDIT:

From the GNU C lib :

/*
  REALLOC_ZERO_BYTES_FREES should be set if a call to
  realloc with zero bytes should be the same as a call to free.
  This is required by the C standard. Otherwise, since this malloc
  returns a unique pointer for malloc(0), so does realloc(p, 0).
*/

By default, this is defined to 1, but other implementation can change that behavior...


The C90 standard specifically said:

If size is zero and ptr is not a null pointer, the object it points to is freed.

So this is how C90 and C++ implementations should behave - nice, simple, and straightforward.

However, for some reason that sentence was removed from the C99 standard.

POSIX currently has the sentence that's in the C90 standard. But, The Austin Group (which handles some aspects of the POSIX standardization) has a defect open on this. Note that the defect report indicates that BSD has the following behavior for realloc(ptr,0):

realloc(ptr,0) only gives NULL on alloc failure, ptr unchanged, errno is ENOMEM

Which I read as saying that ptr is not freed (I don't have a BSD system to check this on).

In other words, it's kind of a mess what should/will happen with realloc(ptr,0) - I wouldn't depend on it freeing the memory. Call free() of that's what you want to do.

I wonder what the rationale for C99 removing that sentence was...

In fact, the C99 standard actually seems to preclude realloc(ptr,0) from simply freeing the block (ie., it doesn't seem to leave this implementation defined at all). The C99 standard says:

... If memory for the new object cannot be allocated, the old object is not deallocated and its value is unchanged

Returns

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

So, if realloc() returns NULL then the new object could not be allocated and the old object must not be freed. But if realloc() returns non-NULL, then you still have the object that must be freed (or some new memory object that must be freed). In other words, if realloc(ptr,0) returns NULL then you are still responsible for freeing ptr. If realloc(ptr,0) returns a non-null pointer, then you're responsible for freeing whatever pointer is returned.

I guess maybe that's why C99 removed that sentence. Note however, that many (most?) implementations do free the block when realloc(ptr,0) is called, regardless of what C99 might have to say about it.

0

精彩评论

暂无评论...
验证码 换一张
取 消