10

The code works as it is supposed to, though it never frees the memory allocated by malloc().

I have tried to free memory in any place that I can, but no matter where I do it, it breaks the program. Specifically, I get a "double free or corruption error." This is more of a question as to what free() and malloc() actually do? All of the problems with free are in the main:

int main(int argc,  char *argv[]){
if(argc!=2){
    exit(1);
}

printf("CSA WC version 1.0\n\n");

int length = strlen(argv[argc-1]);
char file_to_open[length];
strcpy(file_to_open, argv[argc-1]);

//printf("filename:%s\n",file_to_open);

//create counters for output
int count_number_of_lines = 0;
int count_number_of_words = 0;
int count_number_of_characters = 0;

//create int size of default array size
int current_array_size = pre_read(file_to_open);
//printf("number of lines: %i\n",current_array_size);

//create string array of default size
char *strings_array[current_array_size];

//create a pointer to catch incoming strings
char *incoming_string=NULL;

int done=0;
while(done==0){
    incoming_string=get_line_from_file(file_to_open, count_number_of_lines);
    if(incoming_string!=NULL){
        incoming_string=csestrcpy2(incoming_string);
        //printf("incoming line: %s\n",incoming_string);
        strings_array[count_number_of_lines]=(char*)malloc(strlen(incoming_string+1));
        strings_array[count_number_of_lines]=csestrcpy2(incoming_string);
        //printf("added to array:%s\n",strings_array[count_number_of_lines]);
        count_number_of_lines++;
        count_number_of_characters=(count_number_of_characters+(strlen(incoming_string)-1));
    }
    else{
        done=1;
    }

}
//all data is stored in a properly sized array


//count all words in array
int count=0;
int word_count=0;
char *readline;

while(count<current_array_size){
    readline = csestrcpy2(strings_array[count]);
    printf("line being checked: %s", readline);

    int i=0;
    int j=1;

    while( j< strlen(readline)+1 ){
        if(strcmp(readline,"\n")!=0){
            if( (readline[i] == ' ') && (readline[j] != ' ') ){
                word_count++;
            }
            if( (readline[i] != ' ') && (readline[j] == '\n') ){
                word_count++;
            }
        }
        i++;
        j++;
    }
    count++;
}
printf("current word count: %i", word_count);
return 0;
}



char* csestrcpy2(char* src){

int i = 0;
char *dest;
char t;
dest = (char*) malloc(MAX_LINE);

while( src[i] != '\0'){

    dest[i] = src[i];
    i++;

}

dest[i] = '\0';
//printf("length:%i\n",i);
free(dest);

return dest;
}
Piper
  • 1,266
  • 3
  • 15
  • 26
Koffeeaddict4eva
  • 152
  • 1
  • 2
  • 10
  • 1
    There is no reason to copy `file_to_open` out of `argv`, you can just *use* `argv`. – user229044 Sep 13 '11 at 04:51
  • Curious about `incoming_string=csestrcpy2(incoming_string);` Is this just a string copy function? – Coeffect Sep 13 '11 at 04:54
  • 2
    Also, `malloc(strlen(str+1));` is almost certainly wrong. You probably meant `malloc(strlen(str)+1);`. (And many people, including me, recommend omitting the cast - `void *` pointers will be implicitly converted, and it can cause potential problems if you explicitly convert it to the wrong type.) – Chris Lutz Sep 13 '11 at 04:55
  • csestrcopy2(incoming_string); is a string copy method that returns a string that is guaranteed to have a '/0' at the end of the line.... – Koffeeaddict4eva Sep 13 '11 at 05:39
  • Please post the entire code from your csestrcopy2 function because, judging by what you posted in the comments, that's part of your problem. – Coeffect Sep 13 '11 at 06:02
  • I recently edited the code to reflect a change that i made on it! the number times malloc() is in the code has been reduced to one... I would like to thank everyone who has been helping me! – Koffeeaddict4eva Sep 13 '11 at 07:07
  • I also added the csestrcpy code as well – Koffeeaddict4eva Sep 13 '11 at 07:08
  • *note csestrcpy is a funtion from another file.... – Koffeeaddict4eva Sep 13 '11 at 07:11
  • I do see the catch-22 of trying to free the memory AND returning from the csestrcpy2 function where then you can't access the var outside the scope of the function! Maybe use a global var that can serve as a reusable buffer for that function? Then it can be free'd in any scope as well. – Vince K Jan 24 '20 at 02:55

7 Answers7

19

In general you only have to free memory that has been reserved for you dynamically. That means if you have a statement like this:

int *my_int_pointer;
my_int_pointer = malloc(sizeof(int));

than you need to free the memory that was allocated (reserved) by malloc. if you are unsure where to free it than just free it at the end of the program, by using free;

free(my_int_pointer);

In your file it looks like there will be memory allocated whenever there is a new line in the file you read (in the while(done==0) loop). so everytime after the if in the this loop you have to free the memory that was used by the variable.

Furthermore you need to free the memory that was allocated by for the readline variable. But as it was pointed out before you may have a memory leak there.

Hope this helps.

edit: Okay - I was already wondering about the csestrcpy function. Lets have a look at this function:

char* csestrcpy2(char* src){
    int i = 0;
    char *dest;
    char t;
    dest = (char*) malloc(MAX_LINE); /*<<- This allocates memory that has to be freed*/
    while( src[i] != '\0'){
        dest[i] = src[i];
        i++;
    }
    dest[i] = '\0';
    //printf("length:%i\n",i);
    free(dest);                  /* This frees the memory, but you return a pointer */
    return dest;                 /* to this memory. this is invalid.                */
}

What you could however free is the src pointer in that function. but remember: the pointer cannot hold information after the underlying memory is freed! It just points to a place in memory where it should not write or read anymore.

Furthermore the function copys the string as long as there is no '\0'. What happens if there is no terminator? The function keeps on copying from some memory adresses where it should not!

you should not use that function ;)

Kristian Glass
  • 37,325
  • 7
  • 45
  • 73
Florian
  • 512
  • 1
  • 6
  • 12
  • tried to free to free the memory where you said and got the: free(): invalid pointer: 0xb76f5000 maybe this is unfixable – Koffeeaddict4eva Sep 13 '11 at 05:50
  • Also you are correct about the read in... I have to read a file then store each line read in in as a properly sized null terminated string in an array of strings... this actually works just fine... Can I free the memory allocated for that array if i want to read the array later? If i do free it can i still read the array? How much memory can I malloc() before my program gets dead? – Koffeeaddict4eva Sep 13 '11 at 06:03
  • That is not the syntax for `free`. – Oliver Charlesworth Sep 13 '11 at 08:14
  • whoops... i was just recently working with c++ and confused free(ptr); with delete ptr; – Florian Sep 13 '11 at 10:11
  • What will happen if I call call free() on a variable not created with malloc(), for instance, if I receive a pointer to a struct and I call free() on that, will my program crash or is it correct? – Redauser Jan 23 '17 at 11:28
7

There needs to be a call to free() for each successful call to malloc().

That doesn't necessarily mean that you need to have equal numbers of malloc() and free() calls in your code; it means that for every malloc() call that's executed when your program runs, you should call free(), passing it the pointer value you got from malloc(). malloc() allocates memory; free() tells the system that you're done with the allocated memory.

(You can almost certainly get away with not free()ing allocated memory when your program terminates, since it will be reclaimed by the operating system, but just as a matter of style and good practice you should still match malloc()s with free()s.)

I'm ignoring calloc() and realloc() calls.

Keith Thompson
  • 254,901
  • 44
  • 429
  • 631
  • Could you please describe scenario(s) where use of free() is an absolute must? Since OS handles it, why will someone ever get to use it (apart from having "good programming practice")? – Coder Sep 12 '15 at 18:45
  • 3
    @VikasGoel: Consider a program that loops indefinitely, allocating memory on each iteration. If it doesn't free its allocated memory, it will quickly run out. – Keith Thompson Sep 12 '15 at 21:33
3

Dynamic memory allocation (malloc) allocates a memory block of requested size, and returns a pointer to the start of this block.Since we have taken this block from memory so its a good practice to return this back to memory after completion of task.

Now as answer of your question , To be always on safe side you can call free function before making return.

main{
    int *i;
    ..
    ..
    i=(int *)malloc(sizeof(int));
    ...//so something with i
    ..
    free(i);
    return 0;
}
Simon Baars
  • 1,877
  • 21
  • 38
Dayal rai
  • 6,548
  • 22
  • 29
1

Think of malloc and free as "begin" and "end". ANY time you call malloc, do what you need to and once you're done, always call free. Make sure to only free it once, double-free is a runtime error.

If you somehow lose the value returned by malloc (yes, this is what's happening with your code), then you have a memory leak (and the gates of hell open up, yada yada).

To re-iterate: free whatever malloc returns (except null).

Chris Eberle
  • 47,994
  • 12
  • 82
  • 119
  • How do I kill the memory leak? or at least find out where it was? – Koffeeaddict4eva Sep 13 '11 at 05:53
  • You cannot 'kill' a memory leak, it happens when your program terminates without freeing memory it allocated. Most Operating systems keep track of memory allocated and free on their own but there is no guarantee. You would have to restart your operating system to recover the memory. You compile your program with debugging support enabled (-g in gcc) and then use a debugger such as gdb or valgrind. valgrind even has a tool called memcheck which shows list of memories which were allocated (and where) – Nalin Kanwar Sep 13 '11 at 06:09
  • Awesome thanks I also found a way to do a code re-write that needs only one malloc()... I appreciate all your help! – Koffeeaddict4eva Sep 13 '11 at 06:58
  • 1
    @Nalin: sorry, but that is incorrect. The OS does indeed keep track of memory allocated for a particular program. However when the program exits, the OS can and does reclaim all of that memory. The last OS that did *not* do this, iirc was Windows 98 (which is why it needed rebooting so often). – Chris Eberle Sep 13 '11 at 13:03
  • Actually, it is perfectly legal to `free()` a NULL pointer (e.g. returned by malloc in your last sentence). The libc will just do nothing, as specified in the standard. However, some coding guidelines may complain about doing this, as it may show that the programmer has no clear idea of what is going on with the allocated blocks and that there is possible memory leaks elsewhere. – calandoa Sep 13 '11 at 14:10
  • I thought that was just `delete`. Interesting. – Chris Eberle Sep 13 '11 at 14:32
  • @Chris: Thanks for the info. That is what i meant by Modern Operating systems. But most embedded systems don't guarantee this. That is why i mentioned it. Either way, it's bad programming practice to leave memory leaks in your program. :) – Nalin Kanwar Sep 14 '11 at 05:02
0

As a general rule, for every malloc there should be a corresponding free. You cannot however free something twice (as you have noticed by now). I don't see any calls to free in your code, so it's impossible to say where your problem lies, but I noticed right away that you malloc some memory and assign it to readline inside of a loop, yet you don't call free on readline at the end of the loop, so you are leaking memory there.

Ed S.
  • 122,712
  • 22
  • 185
  • 265
  • if i fee it at the end of the loop then the program dies... if i free it after the loop then the program dies... if i free it at the end of the program the program dies.... it seems to go like this for any combination of frees at any point in the program... – Koffeeaddict4eva Sep 13 '11 at 05:52
  • @Koffee: It certainly does not. I meant at the end of each *iteration*. The number of iterations is unknown, so you should be cleaning up after yourself. What if you are reading a huge file? Don't design your code to only work under the most trivial of conditions, and you should get into the habit of writing correct code anyway. – Ed S. Sep 13 '11 at 05:55
0
        i++;
        j++;
        /// free here
        free(readline);
    }
    count++;

}
printf("current word count: %i", word_count);

//free here as well
for(int k = 0; k < count_number_of_lines; k++)
{
    free(strings_array[count_number_of_lines]);
}

return 0;
}

This should work.

In general - any memory allocated dynamically - using calloc/malloc/realloc needs to be freed using free() before the pointer goes out of scope.

If you allocate memory using 'new' then you need to free it using 'delete'.

Jan S
  • 1,831
  • 15
  • 21
  • tried both and they both give me double free or corruption (top): 0x088113c8 – Koffeeaddict4eva Sep 13 '11 at 05:45
  • Have edited the post. i'm sorry, the free should be just after the iterators, before the } and not after. also strings_array[count_number_of_lines]=(char*)malloc(strlen(incoming_string+1)); should be strings_array[count_number_of_lines]=(char*)malloc(strlen(incoming_string)+1)); then try freeing it like shown above - it should work – Jan S Sep 13 '11 at 06:14
  • You've written free(dest) and then you are returning it! It doesn't return a string. you don't need to free the memory there. if you remove that and then free it at the end it should work fine. – Jan S Sep 13 '11 at 08:11
0

This line:

strings_array[count_number_of_lines]=(char*)malloc(strlen(incoming_string+1));

is being overriden by the line next to it, so it can be removed.

You should also add free(readline) after count++ in the last loop to free the memory created by malloc.

alf
  • 18,372
  • 10
  • 61
  • 92
  • i cannot remove that line or the array of strings never fills up thus when i try to access the array of strings later even just to print it it it gives me an array with nothing in it? – Koffeeaddict4eva Sep 13 '11 at 05:43
  • also i tried to add that free and got: double free or corruption (top): 0x088113c8 and the program broke... – Koffeeaddict4eva Sep 13 '11 at 05:43