Question

int main()
{
   char myString = NULL;
   realloc(&myString, 5);
   strncpy((char *)&myString, "test", 5);
}

Seems to work fine but I'm still slightly confused about stack vs heap. Is this allowed? If it is allowed, does myString need to be freed manually or will it be released when it goes out of scope?


Edit: Thanks for the responses, so i presume this is equally illegal

//I want the code to change myString to "tests"
char myString[5] = "test";
realloc(&myString, strlen(myString)+2);
myString[4] = 's';
myString[5] = '\0';
Was it helpful?

Solution

No, this is completely wrong. realloc should only be used to reallocate memory allocated by malloc, what you are doing works only by accident, and will eventually crash horribly

char *myString = malloc(x);
myString = realloc(myString,y);
free(myString)

You are better off using new and delete, and even better off using std::string, however.

OTHER TIPS

Some problems with the code you posted:

  • Yes you need to free everything you allocate with malloc, and realloc, and the other related C style memory allocation functions.
  • I think you meant to have char *myString, not char. Passing in the address of something on the stack (your char) is completely wrong.
  • You need to initialize your myString char pointer to NULL before using it in realloc.
  • You should be passing 4 into strncpy not 5, if you had a larger string you'd be overwriting memory.
  • You should be freeing the buffer you created in your example
  • You should be checking the return value of your realloc call. realloc()

[Regarding realloc's return value:] Upon successful completion with a size not equal to 0, realloc() returns a pointer to the (possibly moved) allocated space. If size is 0, either a null pointer or a unique pointer that can be successfully passed to free() is returned. If there is not enough available memory, realloc() returns a null pointer and sets errno to [ENOMEM].

  • re-alloc will work like malloc when you pass in NULL:

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

A more C++ way to do it:

You tagged this as C++ though, and it's more type safe to use C++'s new operator. Although the new operator does not allow for re-allocations, it will work for allocations and for re-using existing buffers (placement new).

char *myString = new char[5];
strncpy(myString, "test", 4); 
//...
delete[] myString;

or even:

#include <string>

//...

std::string str = "test";

Source of top 2 quotes

This shouldn't work. You're reallocing something that wasn't malloced in the first place. And no, it won't get freed when it goes out of scope - when you use malloc or realloc, it's all up to you.

Update: Your edit doesn't change anything - you're still trying to realloc something that wasn't malloced in the first place. Also, you can't ignore the return value from realloc - if realloc has to move the memory somewhere else, you'll find that in the return. In other words:

char* ptr = malloc(4);
ptr = realloc(ptr, 5);

After realloc, ptr might be pointing to an entirely different place in memory, and continuing to use the original value of ptr could leave you using memory that's been freed and which isn't as big as you think it is.

THIS IS DANGEROUS! This will corrupt your stack. If you were to realloc something on the stack of a function that then returned to main(), you would actually end up overwriting the stack frame and returning somewhere other than main(). THIS IS A POTENTIAL SECURITY HOLE.

Try running the following. If it crashes on realloc, you got lucky. You can do serious damage with something like memcpy(&myString).

int dostuff();

int main()
{
        dostuff();
        return 0;
}

int dostuff()
{
        char myString = NULL;
        realloc(&myString, 5);
        strncpy((char *)&myString, "test", 5);
        return 0;
}

This is what you should never do. Trying to free() or realloc() a stack variable can lead to undefined behaviour including (but not limited to) corrupted stack (leading to unpredictable flow of control), corrupted heap service structures, corrupted user memory. You're lucky if the program just crashes with an AV. It may work in some cases, but you should never try to do so.

Rule of thumb: only return memory to the memory manager it was allocated on. In this case don't try to return the stack variable to the runtime heap.

Your program is syntactically valid C++, but it will produce undefined behaviour because you pass the address of a stack object to the heap allocator. Typically this means that your program will crash when executed.

The stack and the heap are two distinct areas of memory allocated to the process executing your program. The stack grows as you enter a function to hold its arguments and local variables, and it shrinks automatically as you return from the function. The heap, on the other hand, is a separate address region where memory may be obtained on demand, and must be released explicitly when it is no longer needed.

If the address of a local variable is passed to realloc(), it may attempt to free its memory and allocate it elsewhere. Since the address is not from the heap, and realloc() operates on the heap, this will fail. Most likely realloc() will detect the address is not from the heap and abort the program.


Apart from this, the example program contains a few logical errors.


char myString = NULL;

You declare a variable to hold a char, not a string. A C-style string has type char*, i.e. a pointer to char.

Also, the char is assigned NULL, the address zero which is conventionally assigned to invalid pointers. This compiles because the preprocessor replaces NULL by the literal 0. Really, you store a zero byte in the char, which is, also by convention, the terminator of a C-style string.


realloc(&myString, 5);

As mentioned above, this is illegal because you pass the address of a stack object to the heap allocator. This problem remains in your second code example.

Also, you discard the return value. realloc() returns the address where the new memory was allocated. It may not be the same address as before. It may even be NULL, which is realloc()'s way of telling you it went out of memory.


strncpy((char *)&myString, "test", 5);

This is correct, but the cast is redundant.


Here is a more correct version of your program:


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

int main()
{
   /* allocate space for, say, one character + terminator */
   char* myString = (char*) malloc(2);

   /* some code using myString omitted */

   /* get more space */
   myString = (char*) realloc(myString, 5);

   /* write to the string */
   strncpy(myString, "test", 5);

   /* free the memory */
   free(myString);

   return 0;
}

In C++, it is better to avoid realloc() entirely. For example, you could use something like the following:


#include <string>

int main()
{
   std::string myString;

   /* some code using myString */

   myString = "test";

   return 0;
}

You do not have to free myString since it is on the stack (which gets "freed" when leaving scope).

realloc is illegal here, the address has to be NULL or an address returned by an earlier call to realloc, malloc or calloc.

Every variable you declare is on the stack, even a pointer:

int *x;

The variable x is on the stack! It is of type pointer and holds an address.

x = (int *)malloc(sizeof(int));

assigns the address returned by malloc to the variable x! The content of x is an memory address!

The problem with what you're doing is that you're mucking with something that isn't a variable. You defined myString as a char, and are therefore trying to change its address. That's bad.

The function realloc() isn't supposed to change anything passed into it. It takes a pointer to some memory on the heap (or the null pointer, if nothing's already allocated) and returns a pointer to some memory on the heap.

Therefore, you provide either a null pointer or a pointer to something allocated by malloc() or realloc() or calloc(), and store the pointer returned.

Something like

char * myString = NULL;
myString = realloc(myString, 5);

will work, but you will want to free() myString.

In C++, however, use std::string.

In response to your second code example:

Yes, this is also illegal. myString is not allocated with malloc (or calloc), so it can't be reallocated with realloc, or freed with free.

Plus that realloc doesn't take a pointer to a pointer as its first argument. It takes a pointer to allocated memory, and returns another (possibly different) pointer. Write the call like this instead:

myString = realloc(myString, strlen(myString)+2);
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top