Когда я должен использовать free () в C? - PullRequest
7 голосов
/ 13 сентября 2011

Код работает как положено, хотя он никогда не освобождает память, выделенную malloc().

Я пытался освободить память в любом месте, где смогу, но независимо от того, где я это делаю, это нарушает программу. В частности, я получаю «ошибку двойного освобождения или повреждения». Это больше вопрос относительно того, что на самом деле делают free() и malloc()? Все проблемы со свободными в основном:

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;
}

Ответы [ 7 ]

12 голосов
/ 13 сентября 2011

Как правило, вам нужно только освободить память, которая была зарезервирована для вас динамически.Это означает, что если у вас есть такой оператор:

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

, то вам нужно освободить память, которая была выделена (зарезервирована) malloc.если вы не уверены, где его освободить, чем просто освободите его в конце программы, используя free;

free(my_int_pointer);

В вашем файле похоже, что будет выделяться память при появлении новой строки вфайл, который вы прочитали (в цикле while(done==0)).поэтому каждый раз после if в цикле this необходимо освобождать память, которая использовалась переменной.

Кроме того, вам нужно освобождать память, выделенную для переменной readline.Но, как было указано, до того, как у вас может появиться утечка памяти.

Надеюсь, это поможет.

edit: Хорошо - мне уже было интересно узнать о функции csestrcpy.Давайте посмотрим на эту функцию:

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.                */
}

Однако вы можете освободить указатель src в этой функции.но помните: указатель не может содержать информацию после освобождения основной памяти!Он просто указывает на место в памяти, где он не должен больше ни писать, ни читать.

Кроме того, функция копирует строку, пока нет '\ 0'.Что происходит, если терминатора нет?Функция продолжает копировать из некоторых адресов памяти, где она не должна!

Вы не должны использовать эту функцию;)

6 голосов
/ 13 сентября 2011

Для каждого успешного вызова на malloc().

должен быть звонок на free().

Это не обязательно , обязательно означает, что в вашем коде должно быть одинаковое количество вызовов malloc() и free(); это означает, что для каждого malloc() вызова, который выполняется при запуске вашей программы, вы должны вызывать free(), передавая ему значение указателя, полученное из malloc(). malloc() выделяет память; free() сообщает системе, что вы закончили с выделенной памятью.

(Вы почти наверняка можете обойтись без free()ing выделенной памяти, когда ваша программа завершит работу, поскольку она будет возвращена операционной системой, но, как стиль и хорошая практика, вы все равно должны соответствовать malloc() s с free() с.)

Я игнорирую calloc() и realloc() звонки.

3 голосов
/ 01 мая 2013

Динамическое выделение памяти (malloc) выделяет блок памяти запрошенного размера и возвращает указатель на начало этого блока. Поскольку мы взяли этот блок из памяти, поэтому рекомендуется возвращать его обратно в память после завершенияtask.

Теперь, как ответ на ваш вопрос, чтобы всегда быть в безопасности, вы можете вызвать свободную функцию перед возвратом.

main{
    int *i;
    ..
    ..
    i=(int *)malloc(sizeof(int));
    ...//so something with i
    ..
    free(i);
    return 0;
}
0 голосов
/ 13 сентября 2011

Эта строка:

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

переопределяется строкой рядом с ним, поэтому ее можно удалить.

Вы также должны добавить free(readline) после count++ в последнем цикле, чтобы освободить память, созданную malloc.

0 голосов
/ 13 сентября 2011
        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;
}

Это должно работать.

В общем случае - любая память, выделяемая динамически - с использованием calloc / malloc / realloc, должна быть освобождена с помощью free (), прежде чем указатель выйдет за пределы области видимости.

Если вы выделяете память с помощью «new», вам необходимо освободить ее с помощью «delete».

0 голосов
/ 13 сентября 2011

Думайте о malloc и free как о «начале» и «конце».В ЛЮБОЕ время, когда вы звоните malloc, делайте то, что вам нужно, и как только вы закончите, всегда звоните free.Обязательно освобождайте его только один раз, double-free - это ошибка времени выполнения.

Если вы как-то потеряете значение, возвращаемое malloc (да, это то, что происходит с вашим кодом), тогда у вас есть памятьутечка (и врата ада открываются, яда яда).

Чтобы повторить: освободите все, что возвращает malloc (кроме нуля).

0 голосов
/ 13 сентября 2011

Как правило, для каждого malloc должен быть соответствующий free. Вы не можете однако free что-то дважды (как вы уже заметили). Я не вижу никаких вызовов free в вашем коде, поэтому невозможно сказать, где находится ваша проблема, но я сразу заметил, что вы malloc немного памяти и назначаете ее readline внутри цикла, но пока Вы не вызываете free на readline в конце цикла, так что вы теряете память там.

...