C Programming: String Copy Using Heap - c

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

Related

Heap Memory and malloc query

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.

Invalid (Aborted)core dumped error while using free() in C

here's the code:
can anyone explain this issue
how can i deallocate the memory of s in main
char *get(int N)
{
char *s=malloc(10*sizeof(char));
s="hello";
return s;
}
int main()
{
char *s=get(4);
printf(s);
free(s);
}
This here:
s="hello";
Doesn't write "hello" to the allocated memory. Instead, it reassigns s to point to a read-only place where "hello" is stored. The memory you allocated with malloc is leaked, and the free(s); is invalid, because you can't free that read-only memory.
If you want to copy "hello" into s, try strcpy(s,"hello"); instead.
By doing
s="hello";
you're overwriting the returned pointer by malloc() with the pointer to the first element of the string literal "hello", which is not allocated dynamically.
Next, you are passing that pointer (to a string literal) to free(), which causes the undefined behavior.
You may want to change the assignment to
strcpy(s, "hello");
Additionally, by overwriting the originally returned pointer by malloc(), you don't have a chance to deallocate the memory - so you also cause memory leak.
You have two bugs here:
You reassign the pointer s with the reference of the string literal "hello", loosing the memory allocated by malloc
You allocate not enough space for the "hello" string. You need at least 6 characters (not 4)
A variable of type char * is a pointer (memory address) to a character. In C, it is customary to implement strings as zero-terminated character arrays and to handle strings by using variables of type char * to the first element of such an array.
That way, variables of type char * do not actually contain the strings, they merely point to them.
For this reason, the line
s="hello";
does not actually copy the contents of the string, but rather only the pointer (i.e. the memory address) of the string.
If you want to copy the actual contents of the string, you must use the function strcpy instead.
By overwriting the pointer that you use to store the address of the memory allocated by malloc, you are instead passing the address of the string literal "hello" to free. This should not be done. You must instead only pass memory addresses to free that you received from malloc.

What is the difference between assigning a string pointer first to allocated memory and directly to a string literal?

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.

strcat for dynamic char pointers

I need to write a strcat in C. I tried below things:
char * c_strcat( char * str1, const char * str2)
{
char * ret = (char *) malloc(1 + strlen(str1)+ strlen(str2) );
if(ret!=NULL)
{
strcpy(ret, str1);
strcat(ret, str2);
if(str1 !=NULL) free str1; // If I comment this everything will be fine
return ret;
}
return NULL;
}
int main()
{
char * first = "Testone";
char *second = "appendedfromhere";
first = c_strcat(first,second);
if(second !=NULL) free(second);
// I want to store the result in the same variable
}
It crashed whenever I free the str1 memory in the c_strcat function. If I don't free then the memory allocated for the first will be leaked (if I understood properly).
How to store returned value to same variable (first)?
From section 7.20.3.2 The free function of the C99 standard:
The free function causes the space pointed to by ptr to be deallocated, that is, made
available for further allocation. If ptr is a null pointer, no action occurs. Otherwise, if
the argument does not match a pointer earlier returned by the calloc, malloc, or
realloc function, or if the space has been deallocated by a call to free or realloc,
the behavior is undefined.
And str1 (aka first) was not allocated by one of the three dynamic memory allocating functions, causing the crash. Same for second also.
if don't free then the memory allocated for the first will be leaked(if am understood properly).
Memory will be leaked if malloc(), realloc() or calloc() is used and the memory is not free()d at a later point. As the string literal "Testone" is not dynamically allocated it must not be freed.
Note that the pointer NULL check prior to invoking free() is unrequired as free(), as described above, does nothing if the pointer argument is NULL.
Do I cast the result of malloc?
"Testone" & "appendedfromhere" are string literals, constants. They weren't allocated using malloc(), calloc() or realloc(), so you cannot free them.
If you want to store the results to str1 (like strcat does) the memory needed for the concatenated string must be allocated externally. I.e. str1 (first) must be large enough to hold first + second., e.g. by:
char first[100] = "Testone";
Than inside your c_strcat you do not allocate nor free any memory but just write str2 at the end ('\0') into str1.

C: realloc() not functioning as expected

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.

Resources