views:

75

answers:

3

Basically the problem comes down to this:

I load a file, write all the each character into a char* variable which has malloc() the length of the file. Then I return that variable and print it, then I free() the memory for that variable and try to print the variable again which does print it.

I'm very new to C so there is probably something wrong in the way I handle the memory for the variable that holds the text content.

I tried using char[(ftell(file)] instead of malloc and char*, but then the function didn't return anything. That's probably because it's a local variable which gets freed when the function does return, right?

Here's what my code looks like:

main.c:

#include <stdio.h>
#include <stdlib.h>
#include "data/filesystem/files.h"

int main(){
    char *filebuffer = retrieve_file_content("assets/test.txt");
    printf("%s", filebuffer);
    free(filebuffer);
    printf("%s", filebuffer);
    return 0;
 }

files.c:

#include <stdio.h>
#include <stdlib.h>

char *retrieve_file_content(char* path){
    FILE *file;
    file = fopen(path, "r");
    if(file){
        fseek(file, 0L, SEEK_END);
        char *filebuffer = malloc(ftell(file));
        if(filebuffer == NULL){ return NULL; }
        fseek(file, 0L, SEEK_SET);
        int i = 0;
        int buffer = getc(file);
        while(buffer != EOF){
            filebuffer[i] = buffer;
            buffer = getc(file);
            i++;
        }
        fclose(file);
        return filebuffer;
    }else{
        return NULL;
    }
}

test.txt:

heheasdasdas

output:

heheasdasdas
heheasdasdas

Thanks in advance!

+3  A: 

What you observe is undefined behavior. It works for you this time, it might crash the next time. Don't do it.

After you call free() the memory block ownership is passed to the C runtime and the data stored in the block is not modified (the latter is done for performance reasons). It happens that the block is still mapped into the process memory so for you it looks like you can safely read it. However depending on multiple conditions doing so can lead to the program crashing or to the program reading altered data or to any other consequences. Never try to access memory that you've already free()d.

sharptooth
+10  A: 

free just marks that the memory in question is free to be allocated again, that means it can be reused. But it doesn't set the freed memory to any value. Your example is what is called UB (Undefined Behavior). Programs having Undefined Behavior may technically do anything - including wrong/strange behavior, good behavior, or ordering a pizza via skype :)

Armen Tsirunyan
Accepted for the pedagogic explanation and +1 for the joke :)
Ancide
@Ancide: Actually that was not fully a joke - UB can lead to really unpredictable consequences. So if your program techically can order pizza (say the runtime has such function) it can happen that that functionality is triggered. See this real world example: http://stackoverflow.com/questions/908872/whats-the-worst-example-of-undefined-behaviour-actually-possible/3554343#3554343
sharptooth
+1  A: 

The behavior of your program is undefined: the C standard says nothing about what happens to memory after free is called on it, only that you shouldn't use it anymore. Most implementations put it back on a free list, so a next call to malloc may use it. Some return it to the operating system, but only C implementations for small computers are likely to do that. Some wipe it, but only high-security implementations are likely to do that.

I.e.: your program's behavior depends solely on coincidence, and might not work tomorrow/in a year's day/when the moon if full.

larsmans