freeing an double pointer - c

int size_of_daten = 5;
char *data[size_of_daten];
char *normal_Pointer = (char*)malloc(sizeof(char) * 100);
int i;
for(i=0; i<size_of_daten; i++) {
data[i] = (char*)malloc(sizeof(char) * 100);
}
data[0] = "0";
data[1] = "1";
data[2] = "2";
data[3] = "3";
data[4] = "4";
printf("data[2] %s\n",data[2]);
strcpy(normal_Pointer,data[2]);
for(i=0; i<size_of_daten; i++) {
free(data[i]);
}
free(data);
I just tried this... even I freed the array as I malloced it... also I copied the value of data[2] and didn't point at it... so that shouldn't be the problem...

You're trying to copy the strings "0", "1", etc. into your data array: you can't just use = to copy strings, you'll need to use a string library method like strcpy.
Once you assign to your array elements those literal strings, e.g.: data[0]= "0";
, the array elements no longer point to the memory that you've allocated, they point to memory that doesn't belong to you, and you can't use free. You've lost the references to your memory blocks from malloc, causing a memory leak.
Furthermore, you can't do free(data); because it wasn't allocated using malloc: it's an array allocated on the stack.

This is not how you copy data into an array of chars you've previously allocated:
data[0]= "0";
data[1]= "1";
data[2]= "2";
data[3]= "3";
data[4]= "4";
You're overwriting the pointers with the address of 5 new pointers. At this point you've lost the address of the memory you had allocated, and when you call free you're calling it on the statically allocated string "0".
You need to use strcpy to copy bytes from one character array into another:
strcpy(dest[0], "0");
strcpy(dest[1], "1");
/* etc */

With data[0]= "0" you are overwriting whatever malloced address returned by malloc.
What you should be doing instead is
strcpy(data[0], "0");
strcpy(data[1], "1");
...

First, assignment to the elements of data after allocating leaks the previously allocated memory. When you assign a char *, you assign only the char *: it doesn't copy the string, it overwrites the pointer.
Second, you're freeing data declared on the stack. You define data with:
char *data[size_of_daten];
This describes an on-stack array of character pointers. It will go out of scope when your function returns, and freeing it manually will blow up.

Related

Dynamically allocating memory for 2d char array

I am using malloc to dynamically allocate a 2d char array. Unless I set every array index to NULL before free(), I get a segmentation fault when trying to free(). Why do I get a segmentation fault?
#include <stdio.h>
#include <stdlib.h>
int main(void) {
int nrows = 20; int ncolumns = 10;
char ** arr = malloc(nrows * sizeof(char *));
for(int i = 0; i < nrows; i++)
arr[i] = malloc(ncolumns * sizeof(char));
arr[0] = "string1";
arr[1] = "string2";
// does not work without the following code:
// for(int i = 0; i < 20; i++)
// arr[i] = NULL;
for(int i = 0; i < 20; i++)
free(arr[i]);
free(arr);
return 0;
}
When you do this:
arr[0] = "string1";
arr[1] = "string2";
You overwrite the contents of arr[0] and arr[1], which contain the addresses of memory returned from malloc, with the address of two string constants. This causes a memory leak, as that memory is no longer accessible. This is also the reason you crash when you call free because these variables no longer hold the addresses of allocated memory.
What you probably want to do here instead is use strcpy, which will copy the contents of the string literal to the memory you allocated.
strcpy(arr[0], "string1");
strcpy(arr[1], "string2");
Now you can free the memory properly.
Your code is ok, the problem comes from the fact that you are assigning string literals to your array here: arr[0] = "string1";.
You are thus replacing the pointer at arr[0], which is pointing to your allocated memory, with the pointer to a string literal.
Pointers to literals are protected, you cannot free (nor write to them) them because you didn't allocate them.
To solve this problem, use strcpy to copy the value of your literal inside your allocated memory:
strcpy(arr[0], "string1");
strcpy(arr[1], "string2");
= operator does not copy the string it only assigns the pointer. So your malloced memory is not accessible anymore for those array elements and attempt to free it is an Undefined Behavoiur which may lead to the segfault.
You need to copy it using strcpy.
Crashing upon a call to free is a sign of incorrect memory management somewhere else in your code. When you set a pointer to NULL then free it, you are not going to crash, because free(NULL) is guaranteed to be benign by the C Standard ยง 7.22.3.3:
7.22.3.3 The free function
...
If ptr is a null pointer, no action occurs. Otherwise, if
the argument does not match a pointer earlier returned by a memory management
function, or if the space has been deallocated by a call to free or realloc, the
behavior is undefined.
Emphasis mine.
As other answers have noted, you are trying to call free on memory that you didn't explicitly allocate with malloc-family functions (since you overwrote arr[i] pointers with pointers to string literals)
Two things to know:
You have two area in you memory (to make easy t understand) heap and stack
malloc, realloc, calloc allocate ressource from heap. I will say only malloc (but it is the same)
free can only free ressource from heap. Stack is reserver for the compiler (it store function call and other data)
The rule for each ressource you get from malloc you have to free it.
to free simply call the free function (but we can optionally assigne null pointer to be sure it is freed).
char * a = malloc(255);
to free
free(a);/* this is mandatory */
a = NULL;/* we can add this to the first line */
In fact it you take the habit to assign NULL value and one time you access it's value you will have NULL deference error: so you will know where to find error
What you try to do:
alloc a array char ** arr = malloc(nrows * sizeof(char *)); and you free it free(arr);
but you alloc 20 arrays of char arr[i] = malloc(ncolumns * sizeof(char));
you ignore it's value arr[0] = "string1"; (you loose the value returned by malloc so you can't free now arr[0]) we are not in C++. So "string1" is stocked on the stack (so malloc can't free it)
and you call free on it.
what you can do
#include <stdio.h>
#include <stdlib.h>
int main(void) {
int nrows = 20; int ncolumns = 10;
char ** arr = malloc(nrows * sizeof(char *));
for(int i = 0; i < nrows; i++)
arr[i] = malloc(ncolumns * sizeof(char));
free(arr[0]);//know we can loose it value because it is freed
arr[0] = NULL;// in fact we assign a value just after so this line is useless but is educationnal purpose
free(arr[1]);//know we can loose it value because it is freed
arr[1] = NULL;// in fact we assign a value just after so this line is useless but is educationnal purpose
arr[0] = "string1";
arr[1] = "string2";
// does not work without the following code:
// for(int i = 0; i < 20; i++)
// arr[i] = NULL;
for(int i = 2; i < 20; i++)//we start at 2 because the first two value are on the stack
{
free(arr[i]);
arr[i] = NULL;//this is useless because we will free arr just after the loop)
}
free(arr);
arr = NULL;// this is useless because we exit the end of program
return 0;
}

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

Free 2D char array

I need to free an array of pointers. So I have set up a simple error prone example of what I am trying to do.
int main() {
char ** strings = malloc(2);
strings[0] = malloc(sizeof(char)*4);
strings[1] = malloc(sizeof(char)*4);
strings[0] = "ABCD";
strings[1] = "EFGH";
free(strings[1]);
}
I believe I need to free the pointers in reverse order so I started with index one.
However I get this error:
free(): invalid pointer: 0x0000000000400d49 ***
Freeing like free(strings); clears index zero, however calling it again throws the error:
double free or corruption (fasttop): 0x00000000008e5010 ***
What is the correct way to wipe out this pointer array? Or if there is something wrong with how I created the array, please let me know.
strings[0] = "ABCD"
replaces the pointer to allocated memory with a pointer to the string literal "ABCD". You didn't allocate memory for this so can't free it.
Use
strcpy(strings[0], "ABCD");
to copy into the memory you allocated.
Note that you'll still have another couple of problems here. First, you need to allocate space for two pointers in your strings array - you currently only allocate 2 bytes. Second, "ABCD" requires 5 bytes of storage (the 5th byte is for the nul terminator). You therefore either need to allocate 5 bytes for each array or, better, combine allocation and string copying using strdup (a Posix rather than C standard function)
char ** strings = malloc(2 * sizeof(*strings));
strings[0] = strdup("ABCD");
strings[1] = strdup("EFGH");
int main() {
char ** strings = malloc(sizeof(char*)*2);
strings[0] = malloc(sizeof(char)*5);
strings[1] = malloc(sizeof(char)*5);
strcpy(strings[0], "ABCD");
strcpy(strings[1], "EFGH");
free(strings[0]);
free(strings[1]);
free(strings);
return 0;
}
This code strings[0] = "ABCD"; is not doing what you expect.
Instead of copying the bytes to the allocated array you get a memory leak. You re-assign strings[0] to point to string literal equal to "ABCD"(thus the allocated array is leaked). That is why calling free on strings[1] fails. What you need to do is use strcpy:
strcpy(strings[0], "ABCD");
strcpy(strings[0], "EFGH");

Difference between these two pointer to char initialisations

I know this has been answer before, but I can't find the question.
What are the differences between these two initialisations:
int main()
{
char* pch1;
char* pch2;
pch1 = (char*)malloc(sizeof(char) * 5);
strcpy(pch1, "Text");
pch2 = "Text";
}
First: don't cast the return value from malloc - it's a common source of errors. Do I cast the result of malloc?
pch1 = malloc(sizeof(char) * 5);
assigns a pointer to a dynamically allocated block of 5 bytes on the heap.
pch2 = "Text";
should ideally be avoided because it assigns a pointer to a string literal. String literals are read-only on most OSes and is also a common source of mistakes. If you do this you should make the pointer to const
const char * pch2 = "Text";
There are three main differences here:
The first one copies the content of a string literal into dynamic memory, while the second one points to that literal directly.
Modifying pch1 string is legal; modifying pch2 string is illegal
You need to free pch1 to avoid memory leak.
For completeness, consider pch3 which is initialized like this:
char tmp[] = "Text";
char *pch3 = tmp;
This pch3 is modifiable like your pch1, but it does not need freeing, because the content of the string is copied into automatic memory.
pch1 points to heap
you can modify it within bounderies
plus you have to free it
other points to static data segment
you can not modify it
pch1 will use heap memory for storing your data
pch2 - using stack memory

C Allocating memory for array of structures containing multiple char*

I have problem allocating memory for array of structure containing char*.
I have one stracture "Person"
typedef struct
{
char *name;
char *surname;
char *phonenumber;
} Person;
What I want to do is to read some data from file and fill the array (Person *array) of people where I have to dynamically allocate memory.
At the moment, I have something like that:
array = malloc(sizeof(Person) * arraysize);
Person *buff;
char text[100];
char *result;
for(i=0; i<arraysize; i++)
{
buff = &array[i];
fgets(text, 100, f );
//Read first name
result = strtok(text,":");
buff->name= malloc(strlen(result));
buff->name= result;
//Read surname
result = strtok(0,":");
buff->surname = malloc(strlen(result));
buff->surname = result;
//Read phone number
result = strtok(0, ":");
buff->phonenumber = malloc(strlen(result));
buff->phonenumber = result;
}
When I print out the whole array I don't get any valid data. I'm wondering what am I doing wrong. I appreicate for your answers in advance!
The problem is:
result = strtok(text,":");
buff->name= malloc(strlen(result));
buff->name= result;
You need to use strcpy for copying and also the length of the malloced string should be one more than the string length to accommodate the NUL char.
buff->name= malloc(strlen(result) + 1);
This:
buff->name= malloc(strlen(result));
buff->name= result;
is broken. You can't assign "strings" like that in C, you need to copy characters. The pointer returned by malloc() is overwritten by result, leaking memory. Also, you need to include space for the terminator.
So, this should be:
buff->name= malloc(strlen(result) + 1);
strcpy(buff->name, result);
buff->name= result
resets the pointer buff->name to point to the same location in memory as result. If you want to copy in the string contents of result, use strcpy:
strcpy(buff->name, result);
But note that you have to reserve space for the trailing NUL character as well in the call to malloc:
buff->name = malloc(strlen(result) + 1);
If you're on a POSIX system (Linux, Mac OS X, any Unix) you can replace malloc, strlen and strcpy with the much more convenient strdup:
buff->name = strdup(result);
strtok overwrite the pointer everytime. So you lose the pointer to data as the iteration goes.
You can do something like this, if you wish to directly assign the pointer:
result = strtok(text,":");
buff->name= strdup(result);
strdup is POSIX function. So if it's not available you can easily implement it.
you need to copy the text in result in the newly allocated memory block.
now you just allocate memory (assign the pointer to the pointer), then you discard that pointer and assign a new pointer result to it.
you need to strncpy the result to the new memory allocation.
Also strlen does not include the terminating zero byte, so you do not have enough space in the new memory block.
There is a function strdup which does what you want.

Resources