Realloc on NULL-valued (or undefined) pointer

2019-02-05 18:03发布

I was reading about realloc and got confused about a point mentioned there. Consider the code below:

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

int main () {

    int* ptr = NULL;
    ptr = realloc(ptr, 10*sizeof(int));
    return 0;
}

Is there any danger in allocating memory with realloc using the initially NULL-valued ptr? If instead of:

int* ptr = NULL;

I had this:

int* ptr; // no value given to ptr

would it be a problem to call realloc using ptr?

3条回答
别忘想泡老子
2楼-- · 2019-02-05 18:39

With the specific code shown, there is no problem with using the null pointer initially.

If the variable ptr is uninitialized — not set to 0 or NULL — then any call to realloc() using it is dangerous; the behaviour is undefined and if you are lucky, the program will crash, but if you're unlucky, it will appear to work for a while, until something goes wrong later in the program where it will be hard to spot that the trouble is in code executed a long time ago.

There are those who argue it is better to use malloc() for the initial allocation and realloc() thereafter. There is some justice to the suggestion, not least because you probably wouldn't use ptr = realloc(ptr, 0); to free the memory, even though you could do so (so you don't really need malloc() or free() because realloc() can do all three operations). But the C90 standard requires realloc(0, new_size) to work equivalently to malloc(new_size), and I know of no C library that behaves differently (but there might be some; I've only used a few C libraries, albeit mostly the most widely used ones).


However, in a more general case such as the following code, then there is a subtle problem with the code (but it is not to do with the initial null pointer):

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

int main(void)
{
    char    *ptr = NULL;
    size_t   len = 0;
    char     buffer[256];

    while (fgets(buffer, sizeof(buffer), stdin))
    {
        size_t buflen = strlen(buffer) + 1;
        if (buflen > len)
        {
            if ((ptr = realloc(ptr, buflen)) == 0)  // Danger!
                // ... handle memory allocation failure ...
            len = buflen;
        }
        strcpy(ptr, buffer);
        // ... do something with ptr
    }
    free(ptr);
    return 0;
}

What is the danger? The danger is that if the second or a subsequent memory allocation fails and ptr is the only pointer to the allocated memory, you just overwrote its previous value with null. That means you cannot free the allocated memory using ptr any more — you've leaked memory. (For the first allocation, the initial value was 0, the overwritten value was zero, and nothing has changed; there is no memory leak. That's why the loop was added to the code.)

Rule of Thumb

  • Do not write ptr = realloc(ptr, newsize);

Save the new value into a separate variable until you've tested it.

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

int main(void)
{
    char    *ptr = NULL;
    size_t   len = 0;
    char     buffer[256];

    while (fgets(buffer, sizeof(buffer), stdin))
    {
        size_t buflen = strlen(buffer) + 1;
        if (buflen > len)
        {
            char *new_ptr = realloc(ptr, buflen);
            if (new_ptr == 0)
                // ... handle memory allocation failure ...
            ptr = new_ptr;
            len = buflen;
        }
        strcpy(ptr, buffer);
        // ... do something with ptr
    }
    free(ptr);
    return 0;
}

This code does not leak memory on an allocation failure.

Auxilliary recommendation: do not use a variable called new; it will make it difficult to compile with a C++ compiler. Even if you have no intention now of converting to C++ (and even though you would probably end up rewriting the memory management if you do), there's no virtue in using the C++ keyword new as a C variable name...unless you explicitly want to prevent compilation with a C++ compiler.

查看更多
该账号已被封号
3楼-- · 2019-02-05 18:40

Is there any danger in allocating memory using realloc using the initially NULL-valued ptr?

No, that would exactly be like a malloc.

If instead of:

int* ptr = NULL;

I had this:

int* ptr; // no value given to ptr

would it be a problem to call realloc using ptr?

Yes, there would be a problem. If realloc doesn't get a NULL, it will try to expand memory starting from that location, or may try to free and malloc another part of memory. Since uninitialized variables can have any value, chances are very high, they are not a value realloc likes. If you are lucky, your program would immediately crash.

查看更多
迷人小祖宗
4楼-- · 2019-02-05 18:46

Is there any danger in allocating memory with realloc using the initially NULL-valued ptr

None

7.22.3.5

If ptr is a null pointer, the realloc function behaves like the malloc function for the specified size.

For the second part:

int* ptr; // no value given to ptr

would it be a problem to call realloc using ptr?

If you're using uninitialized pointers then that is a very serious problem indeed since you can't predict what their value will be. The function realloc only works correctly for NULL or values obtained from malloc / realloc.

Otherwise, if ptr does not match a pointer earlier returned by a memory management function [...] the behavior is undefined

查看更多
登录 后发表回答