Right use of free function which changes data - c

please, can you tell me if I use free in my function the right way?
I checked my code with valgrind and no errors occured.
void strconcat (char **str1, const char *str2) {
unsigned long str1len = strlen(*str1);
unsigned long str2len = strlen(str2);
char *tempStr = malloc(sizeof(char) * (str1len + str2len + 1));
memcpy(tempStr, *str1, str1len);
memcpy(&(tempStr[str1len]), str2, (str2len + 1));
free(*str1);
*str1 = tempStr;
}
In the main-function I'm calling my function this way:
int main() {
char *str1 = malloc(25);
str1 = strcpy(str1, "First part of the string");
char *str2 = malloc(16);
str2 = strcpy(str2, " - second part.");
printf("%s\n", str2);
strconcat(&str1, str2);
printf("%s\n", str1);
free(str1);
free(str2);
return EXIT_SUCCESS;
}
Thank you for your help!

Yes, you're using it correctly. In strconcat(), you'll lose the memory originally allocated to str1 when you assign the newly concatenated string to it, so you should free() it before that happens. After you return from that function, you still have two dynamically allocated blocks of memory, so you should free those both two.
Valgrind is generally pretty trustworthy, so you should have some confidence in it, provided that you're running through all the relevant different paths of execution.
Whether what you are doing with your function is a good idea, though, is another thing entirely. If someone passed in a pointer to a string literal then your function would fail catastrophically. There are also some other problems with your code, including that strconcat is a reserved identifier, but for what it does, you're using free() correctly.

After free in void strconcat()function you are assinging malloc'd tempStr variable to *str1, So you not getting any error when you debug with valgrind.
Remove *str1 = tempStr line from function, now compile and run the program your program will get crashed. Because of double free.
EDIT:
You have to free all the memory allocated using malloc. You have to free the memory of str1 before assigning to some other variable to avoid memory leak.
free(*str1) - free for memory allocated to str1 in main() function
free(str1) - free for memory allocated to tempStr in strconcat() function.
free(str2) - free for memory allocated to str2 in main function.

Related

Why don't I have to free heap objects when I pass them into a function?

The following program has no memory leaks. My question is, why does str1 and str2 not have to be passed into free(), even though I malloc'd both strings? Please see two commented locations in the code where I attempted to free str1 and str2, uncommenting that code resulted in an error saying I free'd a non-heap object. But from my understanding, str1 and str2 are objects created by malloc, hence are heap objects. I do not understand this contradiction.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char* StrCat(char* s1, const char* s2) {
// Removing const from const char* s2
// made no difference on memory leak error message
char *s, *tmp;
s = tmp = malloc(strlen(s1) + strlen(s2) + 1);
strcpy(tmp, s1);
tmp += strlen(s1);
strcpy(tmp, s2);
//free(str1); free(str2); Why not?
printf("%d\n", s[strlen(s)] == '\0'); // Prints 1
return s;
}
int main(int argc, char** argv) {
char* str1 = malloc(4 * sizeof (char));
str1 = "abc\n";
char* str2 = malloc(6 * sizeof (char));
str2 = "party\n";
char* new = StrCat(str1, str2);
//free(str1); free(str2); Why not?
printf("%s\n", new);
free(new); // Required
return 0;
}
Of course you need to free heap objects, whether you pass them to a function or not. Whatever is returned by malloc() must eventually be free()d, regardless of how you will use it.
Your problem is as follows:
The following line:
char* str1 = malloc(4 * sizeof (char));
allocates memory for 4 characters and stores a reference to it in str1.
The following line:
str1 = "abc\n";
forgets whatever memory str1 was pointing to, (thus causing a memory leak,) and makes str1 point to a new location, in your program's static data segment. This is memory which was never allocated, and therefore may not be freed.
In order to solve your problem, instead of setting str1 to point to "abc\n" you need to use strcpy() to copy "abc\n" to the allocated memory block which is pointed by str1.
Before doing that, do not forget to increment your 4 and your 6 by 1 each, because strings in C also contain a null-terminating byte, so you need to allocate space for 5 and 7 characters respectively.

Segmentation fault in my strcpy

I'm writing my own strcpy due to the fact that the default one in string.h only accept a const char * as a source string to copy from.
I'm trying this very basic prototype (yes, the return isn't meaningful, I'm just trying things):
int copyStrings(char * dest, char * source){
int i=0;
while(source[i]!='\0'){
dest[i]=source[i];
i++;
}
dest[i]='\0';
return 0;
}
and it gives me SIGSEGV, Segmentation Fault error in gdb, at the line dest[i]=source[i], right at the first character. I'm pretty sure dest[i] isn't a string literal, so I should be able to modify it.
What am I doing wrong?
EDIT: here's the calling
int main(){
char * str = (char*)malloc((int)sizeof(double));
char * str2 = (char *)malloc((int)sizeof(int));
str = "hello";
str2 = "hey jude";
copyStrings(str2, str);
free(str);
free(str2);
return 0;
}
This is assigning a string literal to str2 - the very thing that you claim you aren't doing. This is actually the cause of your segfault.
str2 = "hey jude";
It also is causing a memory leak as prior to this, you malloc'd some memory and assigned it to str2 as well. But not enough memory to hold the string. Typically an int is 4 bytes and you need 9 bytes to store that string.
What you want to do is this, which allocates as many bytes as there are in the string, plus an extra one to store the \0 terminating character at the end.
str2 = malloc(strlen("hey jude")+1);
strcpy(str2,"hey jude");
or on some systems you can use POSIX function strdup() which effectively does the job of the above in one handy function call.
str2 = strdup("hey jude");
Let's go at it line by line and see where it goes wrong:
int main(){
char * str = (char*)malloc((int)sizeof(double));
char * str2 = (char *)malloc((int)sizeof(int));
str = "hello";
str2 = "hey jude";
copyStrings(str2, str);
free(str);
free(str2);
return 0;
}
int main(){ - this is an improper definition of main. Should be int main(int argc, char **argv)
char * str = (char*)malloc((int)sizeof(double)); - defines str, then allocates (probably) 8 bytes of memory and assigns its address to str. malloc takes a size_t argument, so the cast (int)sizeof(double) is incorrect. Also, in C the return value of malloc should never be cast. So this line should be char * str = malloc(sizeof(double));
char * str2 = (char *)malloc((int)sizeof(int)); - all the same problems as the preceding line. Should be char *str2 = malloc(sizeof(int));
str = "hello"; - causes a memory leak, because the memory you JUST ALLOCATED two lines earlier is now irretrievably lost. You've got two options here - either don't allocate the memory when defining str or free it first. Let's do the latter:
free(str);
str = "hello";
str2 = "hey jude"; - same problem, similar solution:
free(str2);
str2 = "hey jude";
copyStrings(str2, str); - here you're telling your routine to copy the constant string "hello" over the top of the constant string "hey jude". This will work fine on some systems, but will blow up on other systems. The question is in the treatment of the constant string "hey jude". If it's stored in modifiable memory the code will work just fine. If it's stored in memory which is marked as being unmodifiable, however, it will blow up. It seems that the latter is the case on your system. To fix this you probably want to go back to the previous line and change it to
str2 = malloc(20);
That's more memory than you'll need, but it will work just fine.
free(str); - you're attempting to free the constant string "hello", which is not dynamically allocated memory. This needed to be done prior to the assignment str = "hello";.
free(str2; - same problem as above. This needed to be done prior to the assignment str2 = "hey jude";.
} - correct
Best of luck.

Free a overwritten pointer

I have this problem:
char** words = (char**)calloc(10, sizeof(char*));
for (int i = 0; i < 10; i++) {
words[i] = (char*)calloc(100, sizeof(char));
}
I create a array of strings this way. Than in code I overwrite pointers (words[i])
char* str = calloc(strlen(temp), sizeof(char));
//fill str
words[index] = str;
And when I try to free the memory, I get HEAP CORRUPTION DETECTED error.
for (int i = 0; i < 10; i++) {
free(words[i]);
}
free(words);
Is there any way how to do it?
You are lucky to have got an error! Free-ing unallocated memory is just Undefined Behaviour, so it could work during all your tests and only break when you put code in production...
The rule is NEVER erase a malloc-ed pointer before it has been freed. You may have very good reasons to overwrite the words array (I do not know everything in your code) but in that case you could either use two different arrays:
one that you malloc and keep until you free it
one that you initially load from the former, proceed as you need and do not use it for freeing anything.
As a common alternative, you should free the allocated memory before reusing the pointer:
char* str = calloc(strlen(temp), sizeof(char));
//fill str
free(words[index]); // avoid the memory leak
words[index] = str; // correct because str points to another allocated buffer
Thanks! Now I know I have an error in code.
char* str = calloc(strlen(temp)+1, sizeof(char));
This actually solved the HEAP CORRUPTION DETECTED error, but I will repair the code according to your advices.
It's quite easy actually.
You just need to do this:
char** words = (char**)calloc(10, sizeof(char*));
And the to copy the string to a heap address:
words[i]=strdup(temp);
Simple as this.
strdup is a function from <string.h> that is this:
char* strdup(char* s)
{
char* ret=malloc(strlen(s)+1);
strcpy(ret,s);
return ret;
}
It's pointless to allocate and then copy when you can just do it in 1 simple step.
First of all, by saying
words[index] = str;
you're overwriting the previously allocated pointer, thereby losing the actual pointer (returned by initial call to calloc()), causing memory leak. You should use strcpy() to copy the content, not the pointer itself.
Something like
strcpy(words[index], str);
should do the job for you.
Having said that,
char* str = calloc(strlen(temp) , sizeof(char));
also looks wrong. You are probably missing the space for null-terminator while //fill str part. You may need
char* str = calloc(strlen(temp)+ 1, 1); //sizeof char == 1, guaranteed in C

munmap_chunk(): invalid pointer

I've spotted the error in my program and decided to write a simple one, which would help me understand what's going on. Here it is :
#include <stdio.h>
#include <stdlib.h>
char * first()
{
char * word = malloc(sizeof(char) * 10);
word[0] = 'a';
word[1] = 'b';
word[2] = '\0';
return word;
}
char * second ()
{
char * word = malloc(sizeof(char) * 10);
word = "ab";
return word;
}
int main ()
{
char * out = first();
printf("%s", out);
free(out);
out = second();
printf("%s", out);
free(out);
return 0;
}
The first() function is working properly, but the second() (exactly the free(out) ) genarates error:
Error in `./a.out': munmap_chunk(): invalid pointer: 0x0000000000400714 ***
ababAborted (core dumped)
I don't understand why the first function is correct, but the second isn't. Could anyone explain why?
In the function second(), the assignment word = "ab"; assigns a new pointer to word, overwriting the pointer obtained through malloc(). When you call free() on the pointer later on, the program crashes because you pass a pointer to free() that has not been obtained through malloc().
Assigning string literals does not have the effect of copying their content as you might have thought. To copy the content of a string literal, use strcpy():
strcpy(word, "ab");
In function char * second
char * word = malloc(sizeof(char) * 10);
word = "ab";
The second statement word = "ab"; changes word to point away from the allocated memory.You are not copying the string "ab" to the area of heap allocated by malloc.
And to free a memory that is not allocated by malloc or similar functions crashes your program.
Attempting to free an invalid pointer (a pointer to a memory block that was not allocated by calloc, malloc, or realloc) may affect subsequent allocation requests and cause errors.
You should use here strcpy as also suggested by others.

Allocate memory and save string in c

I was wondering why the following code isnt't working
int main(int argc, char **argv)
{
char *test = (char*) malloc(12*sizeof(char));
test = "testingonly";
free(test);
}
After thinking about it my assumption was that first i allocate space for 12 chars in memory but the assignment in the next line creates a char array on the stack and the memory address of that is passed to test. So free() tries to release space on the stack which is not allowed. Is that correct?
So what would be the correct approach to save a string on the heap? Is the following a common way?
int main(int argc, char **argv)
{
char *test = (char*) malloc(12*sizeof(char));
strcpy(test, "testingonly");
free(test);
}
char *test = (char*) malloc(12*sizeof(char));
+-+-+-+-+-+-+-+-+-+-+-+-+
test--->|x|x|x|x|x|x|x|x|x|x|x|x| (uninitialized memory, heap)
+-+-+-+-+-+-+-+-+-+-+-+-+
test = "testingonly";
+-+-+-+-+-+-+-+-+-+-+-+-+
test + |x|x|x|x|x|x|x|x|x|x|x|x|
| +-+-+-+-+-+-+-+-+-+-+-+-+
| +-+-+-+-+-+-+-+-+-+-+-+-+
+->|t|e|s|t|i|n|g|o|n|l|y|0|
+-+-+-+-+-+-+-+-+-+-+-+-+
free(test); // error, because test is no longer pointing to allocated space.
Instead of changing the pointer test, you need to copy the string "testingonly" into the allocated place using e.g. strcpy or use strdup. Note that functions like malloc and strdup return NULL if insufficient memory is available, and thus should be checked.
char *test = (char*) malloc(12*sizeof(char));
strcpy(test, "testingonly");
+-+-+-+-+-+-+-+-+-+-+-+-+
test--->|t|e|s|t|i|n|g|o|n|l|y|0|
+-+-+-+-+-+-+-+-+-+-+-+-+
or
char *test = strdup("testingonly");
+-+-+-+-+-+-+-+-+-+-+-+-+
test--->|t|e|s|t|i|n|g|o|n|l|y|0|
+-+-+-+-+-+-+-+-+-+-+-+-+
You answered your question already. Essentially , strcpy is the appropriate way of copying string.
The first version doesn't create a string on the stack, but you're correct that you're not allowed to free it after the assignment. String literals are usually stored in constant/read-only sections of memory. The assignment doesn't copy anything, just makes test point to that area of memory. You cannot free it. You also cannot modify that string.
Your second piece of code is correct and usual. You might want to also look into strdup if your implementation has that.
Well you are correct. Now lets examine first piece of code.
char *test = (char*) malloc(12*sizeof(char));
Above code is no issues.
test = "testingonly";
Here you modified the pointer test leading to memory leak. And when you try to free you are not freeing actual allocated pointer but one "testingonly" literal pointing to. Literal points to constant memory which cannot be overridden in usual scenarios.
Now about second piece of code, this will work fine as you explicitly copied data from where literal is residing to heap where your test is pointing.
To your second point yes strcpy is a usual way. Other ways are 'memcpy' if you are copying raw bytes.
NOTE: Literals are not stored on stack. But you cannot modify location where literals are stored.
the code
#include <stdio.h>
int main(int argc, char **argv)
{
char *test = (char*) malloc(12*sizeof(char));
strcpy(test, "testingonly");
printf("string is: %s\n",test);
free(test);
return 0;
}
will work
This is for allocating the memory:
char *string;
string = (char *) malloc(15);
This is for saving the data:
strcpy(str, "kavitajain");
printf("String = %s, Address = %u\n", str, str);

Resources