Can somebody please explain me way the free(test[0]) is giving me a segmentation fault (core dumped)? I've tried to comment out the free and then the program terminates correctly (except from the lost memory). Also if I comment out test[0] = "abcd" and insert the free(...) again it terminates correctly too!?
char **test = (char**) (malloc(sizeof(char*) * 5));
for (int i=0; i<5; i++) {
test[i] = (char*) (malloc(sizeof(char*) * 5));
}
test[0] = "abcd";
free(test[0]);
Use strcpy instead of == , because here, you just gives test[0] the adresse of a static chain "abcd", that cannot be disallocated like that.
Please see #Fvirtman's answer to fix your crash.
Then to prevent leaks :
test is a two dimentional array so you need to free each one of it's sub-arrays first then free test like this :
for (int i=0; i<5; i++) {
free(test[i]);
}
free(test);
You overwrite your pointer test[0] with address of "abcd",which is statically allocated array that resides in read-only area. Add this printf("%p",test[0]); before and after test[0] = "abcd"; for visualisation of what happens.
Related
I was writing a simple program to see how dynamic memory allocations in C works.
#include <stdio.h>
#include <stdlib.h>
int main() {
char* c = (char* ) malloc(sizeof(char) * 1);
int* a = (int* ) malloc(sizeof(int) * 1);
for (int i = 0; i < 10; i++)
*(a+i) = i;
c = "Hello World";
printf("%c\n", *(c+4));
printf("%d\n", *(a+4));
return 0;
}
The output I get is
o
4
I've allocated enough memory to save a single character and an integer. But then, how is a whole string and an array of integers of length 10 getting saved?
Does the memory automatically get extended? Could someone kindly explain how it works?
Thanks.
In accessing the dynamically allocated array a out of bounds, you invoke undefined behavior. The program may do anything, including "working" the way you expected.
int* a = (int* ) malloc(sizeof(int) * 1);
for (int i = 0; i < 10; i++)
*(a+i) = i;
I will suggest a different syntax, and that you not cast the result of malloc.
int* a = malloc(sizeof(int) * 1);
for (int i = 0; i < 10; i++)
a[i] = i;
As for your string:
char* c = (char* ) malloc(sizeof(char) * 1);
c = "Hello World";
You are allocating one byte of memory and c is pointing to it. You then reassign c to point to a string literal. As a result, you can print c without issue. Since the dynamically allocated memory is no longer pointed to, you cannot free it and a very small memory leak is created.
If you wanted to copy Hello World" into the memory c` pointed to initially, you'd write:
strcpy(c, "Hello World");
But this would access out of bounds for c, and we'd be back in the territory of undefined behavior.
Please note that strings in C require a null terminating character at the end. A single char's memory cannot store a string as it only has room for the null terminator.
The assignment c = "Hello World" just causes c to point to the string literal and the single character allocated has been leaked.
You've written beyond the allocated size of the array a but it's not surprise those addresses are accessible to your program so you don't get a protection/segmentation fault.
Your code then ends before you do anything else with malloc() and free() so you never trip over what memory corruption your for-loop may have introduced.
As comments point out "undefined behaviour" includes your program working as intended.
In my experience overwriting the bounds of dynamically allocated memory often appears to work and then crashes about 3 or more allocations later.
Your program is probably terminating before it trips over the mess you've made of it's memory.
In programming breaking things isn't usually a good way to find out how they work.
Curious about what is going wrong with this strcpy.
int main(void){
char *history[10];
for(int i = 0; i < 10; i++){
history[i] = NULL;
}
char line[80];
fgets(line,80,stdin);
strcpy(history[0],line); //This line segfaults
}
You've created an array of NULL pointers. You then tried to copy characters onto NULL. That's a no-no.
EDIT:
Your program could be optimized to this:
void main() {
char line[80];
fgets(line,80,stdin);
}
Your history array is never used to generate any output. So, while others have pointed out you need to allocate memory, technically, you could simply do this:
history[0] = line;
That will be a valid pointer up until the line goes out of scope, which is when history goes out of scope so it won't matter.
You need to allocate memory for history[0]. As history[0] is assigned NULL referencing it or writing to it will/may cause segfault.
something like
//this will create memory for 100 chars
history[0] = malloc(sizeof(char) * 100);
strcpy(history[0],line);
Or
//shortcut for both - this allocate new memory and returns pointer.
history[0] = strdup(line);
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
I have below code where I have commented when I get segmentation fault and when not.
Originally I got segmentation fault and then I could figure out that probably I cannot initialize my char pointer locations like "abcd". But I am not able to understand - WHY?
I thought testString = "abcd"; will put a at first memory address, b at second and so on ...
Segmentation fault occurs when trying to free memory, based on how I initialize memory location.
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
char* testString = malloc(sizeof(char) * 5);
printf("Size of char is: %d\n", sizeof(char));
printf("Size of int is: %d\n", sizeof(int));
for(int i = 0; i < 5; i++)
{
printf("Pointer addresses are: %p\n", testString + i);
}
char* tempPtr = testString + 2;
printf("My temp pointer address = %p\n", tempPtr);
// This gives me segmentation fault ....
testString = "abcd";
// This will not give me segmentation fault ....
//int count = 65;
//for(int i = 0; i < 5; i++)
//{
// testString[i] = count + i;
//}
printf("Printing character...\n");
for(int i = 0; i < 5; i++)
{
printf("Characters are: %c\n", testString[i]);
}
printf("Freeing memory...\n");
free(testString);
//printf("Access after freeing >>%c<<\n", tempPtr[0]);
//free(testString);
}
Based on #M.M. and #Jonathan's comment I understood that with testString = "abcd"; my testString will point to a memory location where string "abcd" was created and since I didn't malloc'ed it I cannot free it. Also, since my original pointer to heap memory (which I got using malloc) is gone, so it is waste of memory or memory lead.
So, does it means that when I use printf statement like printf("Printing character...\n");, this is also a memory leak? Then how do I avoid it? Looping and inserting into char* is certainly a bad idea.
this line:
testString = "abcd";
is overlaying the pointer given by the call to malloc() with the address of the string literal: "abcd" this results in a memory leak because the original pointer to the allocated memory is lost.
In C, when copying a string, it 'should' be handled by the functions: strcpy() and strncpy() which will not corrupt the pointer contained in testString.
strcpy( testString, "abcd" );
strncpy( testString, "abcd", strlen( "abcd" ) );
Naturally, once the pointer to the allocated memory has been overlayed/destroyed by the assignment statement: testString = "abcd";, the new value placed into testString must not be passed to free()
the seg fault would be happening at the call to free(), not at the incorrect assignment of a new pointer to testString.
Using printf is not a memory leak. Memory leaks occur when a pointer is allocated via malloc [or, herein, strdup] and there is no corresponding free call for it.
Also, trying to free a pointer that has not been allocated is another type of error. It [probably] won't segfault, but free will complain.
Here's a simplified version of your program that illustrates some of the ways you can do this:
#include <stdio.h>
#include <string.h>
#include <malloc.h>
int opt_segv;
char *temp = "abcd";
void
dostr(char *str,int modflg)
{
printf("\n");
printf("dostr: %s\n",str);
if (modflg)
str[modflg] = 'm';
printf("dostr: %s\n",str);
}
void
test1(void)
{
int len;
char *testString;
len = strlen(temp);
testString = malloc(len + 1);
strcpy(testString,temp);
dostr(testString,1);
free(testString);
}
void
test2(void)
{
char *testString;
testString = strdup(temp);
dostr(testString,2);
free(testString);
}
void
test3(void)
{
char *testString;
// passing a pointer to a string _constant_ -- do _not_ modify
testString = temp;
dostr(testString,opt_segv ? 3 : 0);
}
int
main(int argc,char **argv)
{
char *cp;
--argc;
++argv;
for (; argc > 0; --argc, ++argv) {
cp = *argv;
if (*cp != '-')
break;
switch (cp[1]) {
case 's': // generate segfault
opt_segv = 1;
break;
}
}
test1();
test2();
test3();
return 0;
}
You can run the program with -s to simulate the string constant modification that caused your segfault.
This question has content relevant to answer of my question but doesn't have detailed answer. #Jonathan's comments answers all my questions but he hasn't put forward a detailed answer so I am writing my answer so that folks who will visit further can have detailed explanation:
I created a pointer and allocated some space on "heap segment" of the memory, now my pointer was pointing to that memory location on heap.
Code relevant for all this is - char* testString = malloc(sizeof(char) * 5);.
Now, when I dis this - testString = "abcd"; then string "abcd" is created in "text/code segment" (or in some implementation data segment) of the memory and memory address is returned and assigned to my pointer testString.
What happens is that my original pointer which was pointing a memory location on heap is lost and the pointer started pointing to a memory location on text/code segment of the memory.
Implication of all this:
It has resulted in memory leak because my original pointer which was pointing to the heap memory is lost, so now I have no way to free that heap memory and hence memory leak.
When I will try to free that memory using free(testString); then I will get segmentation fault (this is exactly what has happened to me) because free() can only be used to free the memory which is allocated using either malloc, calloc or realloc. Now, since the pointer testString is pointing to a memory location on text/code segment and I had not allocated that memory using some C memory allocation method, so I cannot free it using free() and if I do so then I get segmentation fault.
When I do testString = "abcd" (when testString is a pointer) then I cannot access the memory location pointed by testString because the memory allocated is read-only in text/code segment of the memory. So, testString[0] = 'x' will also result in segmentation fault.
What happens when I do printf("hello, world")?:
This will create "hello, world" string as read-only in text/code segment of memory. I verified that it does create in text/code segment in C99 implementation using size command.
I'm working on learning how to properly deal with pointers, arrays etc in C. I'm a little confused on allocating the memory for them and then freeing that memory. The following is some test code I slapped together:
char *test[150000];
char **ptr;
for(int i = 0; i < 150000; i++)
{
test[i] = malloc(15*sizeof(char));
test[i] = "This is a test";
printf("test[%i] = %s located at %p\n",i,test[i],&test[i]);
}
for(int i=0; i < 150000; i++)
{
printf("Trying to free memory from %p\n",&test[i]);
ptr = &test[i];
free(ptr);
printf("Array item %i has been freed...",i);
}
The output yields the following:
[... Truncated]
test[149997] = This is a test located at 0x7fff581fbcc8
test[149998] = This is a test located at 0x7fff581fbcd0
test[149999] = This is a test located at 0x7fff581fbcd8
Trying to free memory from 0x7fff580d6d60
test2(17599,0x7fff7776f310) malloc: *** error for object 0x7fff580d6d60: pointer being freed was not allocated
*** set a breakpoint in malloc_error_break to debug
Abort trap: 6
sh-3.2#
It appears that when I try and free the pointer allocated, I get an error... Any ideas / pointers on where I'm screwing up would be greatly appreciated.
test[i] = malloc(15*sizeof(char));
This is ok, except that (a) it could be written as test[i] = malloc(15);, and (b) you don't check whether malloc succeeded.
test[i] = "This is a test";
This does not copy the contents of the string "This is a test" into the memory you just allocated. Rather, it's a pointer assignment, causing test[i] to point to the memory for the string literal. It creates a memory leak, since you no longer have a pointer to the memory you allocated with malloc. You probably want to use strcpy.
...
ptr = &test[i];
free(ptr);
Here you free the memory assigned to the string literal, not the memory you allocated.
Correction: that's not what it does. It tries to free the pointer object itself, which doesn't even make sense. (Incidentally, the argument to free doesn't have to be an object name; free(&test[i]) would be equally legal -- and equally incorrect.)
Assuming you fix the allocation problem, what you want is simply:
free(test[i]);
char *test[150000];
char **ptr;
for(int i = 0; i < 150000; i++)
{
test[i] = malloc(15*sizeof(char));
/*test[i] = "This is a test";*/ // Fix1
printf("test[%i] = %s located at %p\n",i,test[i],&test[i]);
}
for(int i=0; i < 150000; i++)
{
printf("Trying to free memory from %p\n",&test[i]);
/*ptr = &test[i];*/ //Fix2
free(test[i]); //Fix3
printf("Array item %i has been freed...",i);
}
Fix1:
Heap Memory is allocated and stored into test[i]. So test[i] has valid address. But again test[i] address is overridden using this statement test[i] = "This is a test"; If you want to copy the string into test[i] use strcpy.
Suppose if you like to assign like this test[i] = "This is a test"; do not allocate dynamic memory before this & no need to free also.
Fix2&Fix3:
The allocated address is stored in test[i] not in &test[i]. So just free that address present in test[i]. No need to use intermediate variable also. If required to use intermediate variable prefer to use char *ptr.