If I have a variable, str that I would like to allocate memory to on the heap, I would use malloc() like:
char* str = (char*)malloc(sizeof("Hello"));
malloc() is returning a void* pointer, which is the memory location where my memory is.
So now, I can give it some data
str = "Hello";
So, the memory location is now full, with 6 bytes. Now, I want to increase its size, to contain the string "Hello World". So, I use realloc(). According to man, void* realloc(void *ptr, size_t size) will:
The realloc() function changes the size of the memory block pointed to by ptr to size bytes.
The contents will be unchanged in the range from the start of the region up to the minimum of
the old and new sizes. If the newsize is larger than the old size, the added memory will not
be initialized.
So I assumed that it will return a void* to the new, now bigger memory location, which I can now fill with my new string, so going on the same logic to malloc():
str = (char*)realloc(str, sizeof("Hello World"));
But, this is where the problem is. This will cause:
*** Error in `./a.out': realloc(): invalid pointer: 0x0000000000400664 ***
And in valgrind
Invalid free() / delete / delete[] / realloc()
This suggests that there is something wrong with the pointer, str. So I decided to remove:
str = "Hello";
And it compiles fine, with the following code:
char* str = (char*)malloc(sizeof("Hello"));
str = (char*)realloc(str, sizeof("Hello World"));
I am aware of the fact that pointer to realloc() must come from malloc(), but simply assigning data to it shouldn't cause realloc() to fail, which suggects that I am doing something completly wrong.
So, what am I doing wrong?
And here is the code that fails:
char* str = (char*)malloc(sizeof("Hello"));
str = "Hello";
str = (char*)realloc(str, sizeof("Hello World"));
// str = "Hello World"; - this is what I would to be able to do.
Note: This code is something I have stripped down from a much larger program, just
to demonstrate the problem I am having, so I have removed checks etc.
Also, I am very new to C, so hence the really simple problem (sorry?), but after hours of work and research, I still can't figure out what I am doing wrong - It seems to work fine for everyone else!.
In C you cannot copy around blocks of memory as you tried to do:
str = "Hello";
That is not a valid string copy; instead, it leaves your malloc'd memory unaccounted for ("leaked"), and changes the pointer 'str' to point to a hard-coded string.
Further, because str is now a pointer to a hard-coded, static string, you cannot realloc it. It was never malloc'd to begin with!
To fix this, you want to change: str = "Hello"; to this:
strcpy(str, "Hello");
str = "Hello";
is the problem. You allocated a buffer and made str point to it. You then need to copy into that buffer. Like this:
strcpy(str, "Hello");
But instead you changed the value of the pointer.
When you call realloc, you must pass to realloc, a pointer that was created by an earlier call to malloc, realloc or similar. But you did not do that. Because you modified str.
malloc() is returning a void* pointer, which is the memory location where my memory is.
So far so good
So now, I can give it some data
str = "Hello";
You are right on being able to give that memory some data, but you are wrong on a way of doing it: you cannot reassign the pointer to a string literal - this would create a memory leak. Instead, you should copy the data into the memory block, like this:
strcpy(str, "Hello");
If you do an assignment instead of a copy, the pointer no longer points to something returned by malloc, making it illegal to pass that pointer to realloc.
This instruction:
str = "Hello";
doesn't allocate any memory in the heap.
char* str = (char*)malloc(sizeof("Hello"));
You are allocating memory dynamically to the str. Good. You are cast-ing the return value of malloc(), Not good.
str = "Hello";
You are trying to put the address of the static string "Hello" in str. Why? This is actually overwriting the memory address allocated by malloc(). What str contains is not a dynamically allocated pointer right now. It's a static address, which is not eligible for realloc()/ free() . Also, you are taking yourself into a zone of memory leak. What I think is you need strcpy() instead.
if you want to avoid the reallocation of memory issue use the function strdup :
char *str = strdup("hello");
str = strdup("hello word");
strdup returns a pointer to the storage space containing the copied string. If it cannot reserve storage strdup returns NULL.
Related
I am trying to get my head around dynamic memory allocation and was hoping someone could explain why the following code executes as it does.
#include <stdlib.h>
#include <string.h>
char* create_string(void);
int main(){
char* str1 = NULL;
char* str2 = NULL;
str1 = create_string();
str2 = (char*)malloc(11);
str2 = create_string();
printf("String 1 is: %s", str1);
printf("String 2 is: %s", str2);
free(str1);
}
char* create_string()
{
char* stack_str = "TestString";
char* heap_str = (char*)malloc(strlen(stack_str) + 1);
strcpy(heap_str, stack_str);
if(heap_str == NULL)
{
printf("Oh no");
return NULL;
}
return heap_str;
}
As far as I thought, to allocate memory on the heap, you have to use malloc with a size which allocates a block of memory and then use a function such as strcpy() or memcpy(), as I have done with str2 above (malloc 11 for the size of "TestString" plus one for the null terminator.)
I am just confused why assigning the result of create_string to str1 which is a null pointer which has not been allocated a block of memory produces the same output as str2.
Many thanks in advance!
"As far as I thought, to allocate memory on the heap, you have to use malloc with a size which..."
size in malloc() is number of bytes which is unsigned integer. Therefore syntactically str2 = (char*)malloc(11); is correct.
Both str1 and str2 are pointing to different memory locations from the heap containing "TestString". This is according to what you have programmed. However
str2 = (char*)malloc(11); returns 11 bytes of memory that can store character data type and returns a pointer to this location in heap. There is no issue in this.
However, in your code you have leaked this allocation when you assign create_string() pointer to it.
It is not wroking exactly as you think.
Firstly, C has constant strings, which will be initialized by double quotes. Those objects when used, actually return a pointer that points to the location of the initialized constant string array.
char * ptr="something" //"something" return a pointer to the location of the string array
// and is assigned to the ptr.
You don't need to allocate memory for constant string as they are managed by compilers. What's happening in the code is stack_str locates to this constant string array which is managed by the compiler. So it is always present. You create a memory block and stores the address in heap_str, and copies the stack_str contents to the dynamically allocated memory, and returns the pointer.
In effect,
str2 = (char*)malloc(11);
is not used for anything and is wasted. Hope you understands.
Edit: In your create_str(), you check heap_str isn't NULL AFTER strcpy(). If the malloc() failed for some reason, the program will still crash even if you check for NULL.
Everybody knows that you have to free() pointers, when you use malloc() because the memory is allocated in the heap, which is not kept account of by the process.
But why don't I have to use free() when assigning a pointer without a heap:
char* text0 = calloc(20, sizeof (char));
strncpy(text0, "Hello World", 20); // Remember to use `free()`!
char* text1 = "Goodbye World!"; // No need for `free()`?
Isn't text1 also a pointer on the stack pointing to the memory allocated on the heap? Why is there no need for free()?
The string constant "Goodbye World!" is placed in a global, read-only section of memory at program startup. It is not allocated on the heap. Same goes for "Hello World".
So after the assignment, text1 points to this static string. Since the string does not exist on the heap, there's no need to call free.
free must be used for all memory allocated with malloc. You allocate memory from the heap and must return it so you can use it later again.
char* text0 = calloc(20, sizeof(char)); // this memory must be freed.
In:
text0 = "Hello World";
you ovewrite the pointer to the allocated memory. The memory is now lost and cannot be reclaimed/reused again.
Note the parenthesis around char in sizeof(char) and note that I dropped the * before text0 as you are assigning the address of the constant string to a variable of type "pointer to character". Turn warnings on when compiling!
You should have done:
free(text0);
text0 = "Hello World"; // DON'T use `free()`!
Note again I dropped the *. More reasons to turn warnings on when compiling.
char* text1 = "Goodbye World!"; // No need for `free()`?
No, no need to call free because you did not allocate from the heap.
char* StringCopy(const char* string) {
char* newString;
int len;
len = strlen(string) ;
newString = malloc(sizeof(char)*len);
strcpy(newString, string);
return(newString);
}
Above code works even though newString is local and should be deallocated at the end of the function. I am new to C, any link which explain this or explanation would be very helpful. I mean should not we get an error like this: address of stack memory associated with local
variable 'newString' returned?
newString is a local variable in the scope of the StringCopy function. It is assigned a pointer which points to the malloc'ed memory.
When we return from this function, the variable newString would be deallocated. However, the memory area allocated (in which the newString pointer points to) is not. The caller of this function would still be able to access the memory area through the returned pointer.
Note: You have to check malloc's return value because it might return NULL.
The value of newString is the address of the string on heap.
Above code return the value of newString.
The string on heap would not be destroyed until you free() it or process exit().
You are also overwriting the malloc'ed memory by one byte... Don't forget the null char terminator takes one; you need to add one to len
So my understanding is that these two block of codes are valid and do the same thing.
1.)
char *ptr = malloc(5);
ptr = "hi";
2.)
char *ptr = "hi";
I would want to know the difference between the two like if there any advantages of one over the other.
The former is a bug, and that code should never have been written.
It overwrites the pointer returned by malloc() with the address of a string literal, dropping the original pointer and leaking memory.
You must use strcpy() or some other memory-copying method to initialize newly allocated heap memory with a string.
The second just assigns the (run-time constant) address of the string literal to the pointer ptr, no characters are copied anywhere.
The first bit is a possible memory leak, the second relies on the implicit const storage class being used, and assigns the memory address of an immutable string to a pointer.
Basically:
char *ptr = malloc(5);//allocates 5 * sizeof *ptr
//then assigns the address where this block starts to ptr
//this:
ptr = "hi";//assigns position of 'h','i', '\0' in read-only mem to ptr
Now, the address you've allocated, that ptr pointed to, still is allocated. The difference is that you have no "handle" on it anymore, because ptr's value changed. There's no pointer pointing to the dynamic memory you allocated using malloc, so it's getting rather tricky to manage the memory... You probably won't be able to free it, and calling free on ptr now will result in undefined behaviour.
If you write:
char *ptr = "hi";
Then you're actually writing:
const char *ptr = "hi";
Which means you can't change the string to which ptr points:
ptr[0] = 'H';//IMBOSSIBRU
Alternatives are:
char string[] = "Hi";//copies Hi\0 to string
//or
char *ptr = malloc(5);
strcpy(ptr, "hi");//requires string.h
The difference between the two snippets above is that the first creates a stack array, the second allocates a block of memory on the heap. Stack memory is easier to manage, faster and just better in almost every way, apart from it being less abundant, and not really usable as a return value...
There is a pool of string literals for every process. Whenever you create a string literal inside your code, the literal is saved in the pool and the string's address (i.e. an address pointing somewhere to the pool) is returned. Therefore, you are creating a memory leak in your first option, because you are overwriting the address you received with malloc.
In the first case
char *ptr = malloc(5);
ptr = "hi";
There is a memory leak and later you are pointing ptr to a string literal "hi" which does require any memory from the heap (that's why there is memory leak).
But if you are allocating the memory and if you are using
strcpy (ptr, "hi");
then if you wish you can modify it
strcpy (ptr, "hello")
with one condition that you allocate sufficient memory before.
But in your case you are assigning a pointer ptr with a string literal, here you will not be able to modify it
ptr = "hello" // not valid. This will give a segmentation fault error
In your second case there is no memory leak and you are making a pointer to point to a string literal and thus it's value cannot be modified as it will be stored in read only data segment.
I have simple code,
#include "stdafx.h"
#include <malloc.h>
int main()
{
char *p = (char*) malloc(10);
p = "Hello";
free(p);
return 0;
}
This code is giving run time exception while terminating. Below is error snippiest,
Microsoft Visual C++ Debug Library
Debug Assertion Failed!
Program: ...\my documents\visual studio 2010\Projects\samC\Debug\samC.exe
File: f:\dd\vctools\crt_bld\self_x86\crt\src\dbgheap.c
Line: 1322
Expression: _CrtIsValidHeapPointer(pUserData)
For information on how your program can cause an assertion
failure, see the Visual C++ documentation on asserts.
(Press Retry to debug the application)
Abort Retry Ignore
p = "Hello"; makes p point to a string literal and discards the previously assigned value. You can't free a string literal. You can't modify it.
If you want p to hold that string, just use
char* p = "Hello";
or
char p[] = "Hello";
if you plan on modifying it.
Neither requires free.
This is how you write a string in the memory allocated by malloc to a char pointer.
strcpy(p, "Hello");
Replace the line
p = "Hello";
with the strcpy one & your program will work fine.
You also need to
#include <string.h>
malloc returns a pointer to allocated memory. Say the address is 95000 (just a random number I pulled out).
So after the malloc - p will hold the address 95000
The p containing 95000 is the memory address which needs to be passed to free when you are done with the memory.
However, the next line p = "Hello"; puts the address of the string literal "Hello" (which say exists at address 25000) into p.
So when you execute free(p) you are trying to free 25000 which wasn't not allocated by malloc.
OTOH, when you strcpy, you copy the string "Hello" into the address starting at p (i.e. 95000). p remains 95000 after the strcpy.
And free(p) frees the right memory.
You can also avoid the malloc and use
char *p = "Hello";
However, in this method, you cannot modify the string.
i.e. if after this you do *p = 'B' to change the string to Bello, it becomes an undefined operation. This is not the case in the malloc way.
If instead, you use
char p[] = "Hello";
or
char p[10] = "Hello";
you get a modifiable string which need not be freed.
p = "Hello";
free(p);
Since Hello is statically allocated, you cannot free it. I'm not sure why you allocate some memory just to throw the pointer away by changing it to another pointer, but that has no effect. If you do this:
int i = 1;
i = 2;
i has no memory that it once held a 1, it holds a 2 now. Similarly, p has no memory that it once held a pointer to some memory you allocated. It holds a pointer to an immutable constant now.
this is a nice one.
the char sequence "hello" is constant and therefore placed niether on the heap nor the stack, but in the .bss/.data segment. when you do p="hello" you make p point to the address of the string hello in that segment instead of the memory you alocated on the heap using malloc. when you go to free p it tries to free the memory in the .bss/.data segment, and naturally fails.
what you probably want is something like strcpy(p,"hello"); which goes over every char in "hello" and places it in the memory pointed to by p. essentially creating a copy of the string "hello" at memory address p.
If you want to copy the contents of the string "Hello" to the memory you allocated, you need to use strcpy:
strcpy(p, "Hello");
The line
p = "Hello";
assigns the address of the string literal "Hello" to the pointer p, overwriting the pointer value that was returned from malloc, hence the crash when you call free.