views:

1420

answers:

9

What does malloc(0) returns? Would the answer be same for realloc(malloc(0),0) ?

#include<stdio.h>
#include<malloc.h>
int main()
{
        printf("%p\n", malloc(0));
        printf("%p\n", realloc(malloc(0), 0));
        return 0;
}

Output from linux gcc:

manav@manav-workstation:~$ gcc -Wall mal.c
manav@manav-workstation:~$ ./a.out
0x9363008
(nil)
manav@manav-workstation:~$

The output keep changing everytime for malloc(0). Is this a standard answer? And why would anyone be interested in getting such a pointer, other than academic research?

EDIT:

If malloc(0) returns dummy pointer, then how does following works:

int main()
{
    void *ptr = malloc(0);
    printf("%p\n", realloc(ptr, 1024));
    return 0;
}

EDIT:

The following code outputs "possible" for every iteration. Why should it not fail ?

#include<stdio.h>
#include<malloc.h>
int main()
{

        int i;
        void *ptr;
        printf("Testing using BRUTE FORCE\n");
        for (i=0; i<65000; i++)
        {
                ptr = malloc(0);
                if (ptr == realloc(ptr, 1024))
                        printf("Iteration %d: possible\n", i);
                else
                {
                        printf("Failed for iteration %d\n", i);
                        break;
                }
        }
        return 0;
}
+11  A: 

In C89, malloc(0) is implementation dependent - I don't know if C99 has fixed this or not. In C++, using:

char * p = new char[0];

is well defined - you get a valid, non-null pointer. Of course, you can't use the pointer to access what it points to without invoking undefined behaviour.

As to why this exists, it is convenient for some algorithms, and means you don't need to litter your code with tests for zero values.

anon
@Neil: `malloc(0)` is the same in C99.
Alok
@Alok: that's just plain false. C99 allows `malloc(0)` to return 0, and good implementations do so.
R..
@R. I think the point is that C99 doesn't *require* implementations to return `0` or non-`0` for `malloc(0)`.
Alok
+4  A: 

C99 standard

If the space cannot be allocated, a nullpointer is returned. 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.

Kornel Kisielewicz
+4  A: 

The comp.lang.c FAQ has the following to say:

The ANSI/ISO Standard says that it may do either; the behavior is implementation-defined (see question 11.33). Portable code must either take care not to call malloc(0), or be prepared for the possibility of a null return.

So, it's probably best to avoid using malloc(0).

unwind
But the same pointer returned by malloc(0), if not NULL, can be used by realloc() to point to some valid memory location. Like realloc(malloc(0), 1024);
Manav MN
@Manav: It actually works with NULL too, `realloc(NULL, 1024)` is the same as `malloc(1024)`
Hasturkun
Can ever malloc(0) and realloc(malloc(0), 1024) return same pointers ???if (malloc(0) == realloc(malloc(0), 1024) printf("possible");
Manav MN
+25  A: 

malloc(0) is Implementation Defined as far as C99 is concerned.

From C99 [Section 7.20.3]

The order and contiguity of storage allocated by successive calls to the calloc, malloc, and realloc functions is unspecified. The pointer returned if the allocation succeeds is suitably aligned so that it may be assigned to a pointer to any type of object and then used to access such an object or an array of such objects in the space allocated (until the space is explicitly deallocated). The lifetime of an allocated object extends from the allocation until the deallocation. Each such allocation shall yield a pointer to an object disjoint from any other object. The pointer returned points to the start (lowest byte address) of the allocated space. If the space cannot be allocated, a null pointer is returned. 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.

Prasoon Saurav
if a non-NULL pointer is returned, then what's it's usage? why would they implement such behavior ?
Manav MN
it doesn't make much sense to return a non-null pointer, but so does malloc(0); the specification leaves this one open so a compiler builder may choose not to handle malloc(0) specifically, so that all the other mallocs are a nanosecond faster (because the check for 0 is ommited)
ammoQ
Simplicity. In some cases, it may simplify the underlying runtime library if it doesn't have to have any special handling of this special case. :)
jalf
PJ Plauger (C Standard Committee member) in one of his articles said their were huge arguments about this, and in the end they chickened out and left it to the implementation.
anon
@Manav: it might be used as a tag-pointer: it's a pointer that's definitely distinct from any other valid pointer and that's not NULL.
Joachim Sauer
returning a non null pointer in the case of malloc(0) is consistent and helps distinguish it from the error case of returning NULL, which may be returned from any argument to malloc, e.g. malloc(4).
Alex Brown
From C99 Section 7.20.3: "...,except that the returned pointer shall not be used to access an object." I am using the same pointer in realloc later, it may be possible that realloc returns the same pointer as malloc(0) for the allocated memory, like realloc(malloc(0), 1024). Can this scenario occur ?
Manav MN
Huge arguments about this.. christ, what the hell is the matter with people?
BlueRaja - Danny Pflughoeft
@Joachim: why would it be distinct from another pointer? Sometimes implementations round all requests up to be a multiple of the machine word size, so `malloc(0)` and `malloc(2)` might both return pointers to a (say) 8-byte buffer.
TMN
@BlueRaja: that's their job, to argue the pros and cons of various proposals. In this case, always returning a null pointer is convenient for some people, whereas making a 0-sized allocation is convenient for others. The committee is *supposed* to consider both. Unfortunately the compromise they came up with only helps platform-specific code, and is useless to anyone trying to code portably.
Steve Jessop
@TMN: because "Each such allocation shall yield a pointer to an object disjoint from any other object."
Bill
From the linux source code of malloc, it seems they return a free pointer without checking the condition (len == 0). The return value is, retval = (void *) bdesc->freeptr; that's why a free pointer reference is returned. It seems going by the source code that NULL is returned in case of malloc(0) only when there is no enough memory left.
Manav MN
@Bill: I thought Joachim was implying that `malloc(0)` returned a special kind of pointer that was somehow distinguishable from pointers to non-zero-size storage. I was simply pointing out that just because you ask for zero bytes off the heap doesn't mean that `malloc()` doesn't allocate anything. I probably should have worded my last sentence to be "...pointers to (say) 8-byte buffers", to make it clear that pointers to separate regions were being returned.
TMN
@TMN: Ah, I think Joachim was saying that any two pointers `a` and `b` returned by malloc(0) will satisfy `a != b` . (Assuming malloc doesn't return NULL for malloc(0), of course.)
Bill
@Prasoon: why all those minor edits? :-)
Alok
@Alok: Imperfection sucks! :P
Prasoon Saurav
@Prasoon: Really? Will you change it to just italics now? IMHO, such minor edits are not worth the negative cost of bumping a question to the front page again and again.
Alok
@Alok:Yeah that's true, will take care of it next time. _Will you change it to just italics now?_ Huh,pardon me?
Prasoon Saurav
@Prasoon: Thanks a lot. I like making my posts better too, so I really appreciate the idea of editing for perfection, but the website showed me that your last edit was to change the quote from the standard from bold italics to bold. I figured your next step might be to change it to just italics! (Which is what I would have preferred, since bold should be used rarely, if ever). :-)
Alok
@Alok: Yes, thats again true. I just wanted to make sure that the relevant statement of the standard is in bold(just to draw attention). I don't exactly remember why I italicised it that day.
Prasoon Saurav
@Prasoon: No problem. Sorry if I seem rather nit-picky - just for the record: that was a minor point indeed, and I appreciate your answers a lot. Cheers!
Alok
@Alok: That's perfectly fine. I appreciate you. :-)
Prasoon Saurav
+2  A: 

See C99, section 7.20.3:

If the size of the space requested is zero, the behavior is implementationdefined: 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 valid for all three allocation functions (ie calloc(), malloc() and realloc()).

Christoph
+2  A: 

I think it depends. I checked the Visual Studio 2005 sources and saw this in the _heap_alloc function:

if (size == 0)
    size = 1;

I think that in many cases you may want a valid pointer, even when asking for zero bytes. This is because this consistent behavior makes it easier to check your pointers because: if you have a non-NULL pointer it's OK; if you have a NULL pointer you probably have a problem. That's why I think that most implementations will return a valid pointer, even when asking for zero bytes.

Patrick
I've often seen a general adjustment like `size = (size+WORD_LEN)%WORD_LEN;` This keeps the blocks in the heap word-aligned, which often improves access time (especially for block transfers).
TMN
The blocks in the heap will be more than word aligned in most systems; typically, all blocks will be aligned on a multiple of 8 bytes; many will be aligned on a multiple of 16 bytes. The return value must be sufficiently well aligned for any use. For many systems, that means that if it is used for a double, it must be aligned on a multiple of 8 bytes; for some systems, a long double may be 16 bytes, and so on. And even though Intel chips may handle misaligned data, there is a performance penalty in doing so which malloc() et al should - and do - avoid.
Jonathan Leffler
A: 

If malloc(0) returns dummy pointer, then how does following works:

void *ptr = malloc(0);

printf("%p\n", realloc(ptr, 1024));

I don't know what you mean by "dummy pointer". If malloc(0) returns non-NULL, then ptr is a valid pointer to a memory block of size zero. The malloc implementation saves this information in an implementation-specific way. realloc knows the (implementation-specific) way to figure out that ptr points to a memory block of size zero.

(How malloc/realloc/free do this is implementation-specific. One possibility is to allocate 4 bytes more than requested and store the size just before the memory block. In that case, ((int *)ptr)[-1] would give the memory block size, which is 0. You should never do this from your code, it's only for use by realloc and free).

user9876
@user9876: "If malloc(0) returns non-NULL, then ptr is a valid pointer to a memory block of size zero."... How do you allocate a valid memory block of size 'zero' as you said in your post?
Manav MN
How does your user application do it? You call malloc(0) (if you're on a system where that returns non-NULL). How does the system implement that? That's a bit like asking how you can have a file on disk with a size of zero. It's still a valid file on disk, with all the usual metadata (directory entries etc), it just has a size of zero.
user9876
+2  A: 

One point nobody cared to talk about yet, in your first program is that realloc with length 0 is the same thing as free.

from the Solaris man page:

 The realloc() function changes the size of the block pointed
 to by ptr to size bytes and returns a pointer to the (possi-
 bly moved) block. The contents will be unchanged up  to  the
 lesser  of  the new and old sizes. If ptr is NULL, realloc()
 behaves like malloc() for the specified size. If size  is  0
 and  ptr is not a null pointer, the space pointed to is made
 available for further allocation by the application,  though
 not returned to the system. Memory is returned to the system
 only upon termination of the application.

If one doesn't know that it can be a source of bad surprise (happened to me).

tristopia
Funny, I mentioned this in the duplicate question here... http://stackoverflow.com/questions/2022335/whats-the-point-in-malloc0/2133585#2133585
tommieb75
+14  A: 

Others have answered how malloc(0) works. I will answer one of the questions that you asked that hasn't been answered yet (I think). The question is about realloc(malloc(0), 0):

What does malloc(0) return? Would the answer be same for realloc(malloc(0),0)?

The standard says this about realloc(ptr, size):

  • if ptr is NULL, it behaves like malloc(size),
  • otherwise (ptr is not NULL), it deallocates the old object pointer to by ptr and returns a pointer to a new allocated buffer. But if size is 0, C89 says that the effect is equivalent to free(ptr). Interestingly, I can't find that statement in C99 draft (n1256 or n1336). In C89, the only sensible value to return in that case would be NULL.

So, there are two cases:

  • malloc(0) returns NULL on an implementation. Then your realloc() call is equivalent to realloc(NULL, 0). That is equivalent to malloc(0) from above (and that is NULL in this case).
  • malloc(0) returns non-NULL. Then, the call is equivalent to free(malloc(0)). In this case, malloc(0) and realloc(malloc(0), 0) are not equivalent.

Note that there is an interesting case here: in the second case, when malloc(0) returns non-NULL on success, it may still return NULL to indicate failure. This will result in a call like: realloc(NULL, 0), which would be equivalent to malloc(0), which may or may not return NULL.

I am not sure if the omission in C99 is an oversight or if it means that in C99, realloc(ptr, 0) for non-NULL ptr is not equivalent to free(ptr). I just tried this with gcc -std=c99, and the above is equivalent to free(ptr).

Edit: I think I understand what your confusion is:

Let's look at a snippet from your example code:

ptr = malloc(0);
if (ptr == realloc(ptr, 1024))

The above is not the same as malloc(0) == realloc(malloc(0), 1024). In the second, the malloc() call is made twice, whereas in the first, you're passing a previously allocated pointer to realloc().

Let's analyze the first code first. Assuming malloc(0) doesn't return NULL on success, ptr has a valid value. When you do realloc(ptr, 1024), realloc() basically gives you a new buffer that has the size 1024, and the ptr becomes invalid. A conforming implementation may return the same address as the one already in ptr. So, your if condition may return true. (Note, however, looking at the value of ptr after realloc(ptr, 1024) may be undefined behavior.)

Now the question you ask: malloc(0) == realloc(malloc(0), 1024). In this case, let's assume that both the malloc(0) on the LHS and RHS returns non-NULL. Then, they are guaranteed to be different. Also, the return value from malloc() on the LHS hasn't been free()d yet, so any other malloc(), calloc(), or realloc() may not return that value. This means that if you wrote your condition as:

if (malloc(0) == realloc(malloc(0), 1024)
    puts("possible");

you won't see possible on the output (unless both malloc() and realloc() fail and return NULL).

#include <stdio.h>
#include <stdlib.h>

int main(void)
{
    void *p1;
    void *p2;

    p1 = malloc(0);
    p2 = realloc(p1, 1024);
    if (p1 == p2)
        puts("possible, OK");

    /* Ignore the memory leaks */
    if (malloc(0) == realloc(malloc(0), 1024))
        puts("shouldn't happen, something is wrong");
    return 0;
}

On OS X, my code didn't output anything when I ran it. On Linux, it prints possible, OK.

Alok
@Alok: Great job. I checked the condition on Linux if (malloc(0) == realloc(malloc(0), 1024). It is failing everytime !
Manav MN
When you say "failing", you mean the program above prints "shouldn't happen, something is wrong"?
Alok
@downvoter: it will be nice to see an explanation.
Alok