what does malloc(0) return? [duplicate]

2019-01-03 15:29发布

This question already has an answer here:

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;
}

9条回答
淡お忘
2楼-- · 2019-01-03 16:16

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.

查看更多
Rolldiameter
3楼-- · 2019-01-03 16:16

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).

查看更多
唯我独甜
4楼-- · 2019-01-03 16:21

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.

查看更多
登录 后发表回答