Как освободить выделенную память без потери ее стоимости - PullRequest
0 голосов
/ 10 октября 2018

Здравствуйте, я написал эту функцию на C, которая принимает строку слов и возвращает двумерный массив символов, в котором каждый регистр инициализируется словом в правильном порядке, я скомпилировал и выполнил назначенную задачу

char **decompose_string(char *string)
{
int i,j=0;
char* temp=malloc(sizeof(char*));
char **words_array=malloc((string_words_number(string)+1)*sizeof(char*)); //string_words_number return the number of words in string string
for(i=0;i<string_words_number(string);i++)
{   

    temp=NULL;
    int l=0;
    while(string[j]!=' ' && *string)
    {   
        temp=realloc(temp,(l+1)*sizeof(char));
        temp[l]=string[j];
        j++;l++;
    }
    j++;
    temp[l]='\0';
    tab_mots=realloc(words_array,(string_words_number(string)+1)*sizeof(char)*(j-1));
    words_array[i]=temp;

}
words_array[i]=NULL;
return words_array;}

И мой главный:

int main()
{
char* string1= "word1 and word2 and word3";
printf("Our initial string: %s\n",string1);
char** words_array1;
printf("After decomposition:\n");
words_array1=decompose_string(string1);
display_words_array(words_array1); //displays each element of the array in a line
words_array1=destroy_array(words_array1);
return 0;}

Но когда я выполнил команду valgrind, чтобы увидеть, есть ли какие-либо утечки памяти, это был результат:

==4648== Memcheck, a memory error detector
==4648== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al.
==4648== Using Valgrind-3.11.0 and LibVEX; rerun with -h for copyright info
==4648== Command: ./test_csvl
==4648== 

Our initial array: word1 and word2 and word3
After decomposition:
==4648== Invalid write of size 1
==4648==    at 0x4009D9: decompose_string (in /home/omaima/2I001/TME3/test_csvl)
==4648==    by 0x40078F: main (in /home/omaima/2I001/TME3/test_csvl)
==4648==  Address 0x5204634 is 0 bytes after a block of size 4 alloc'd
==4648==    at 0x4C2FD5F: realloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==4648==    by 0x40097D: decompose_string (in /home/omaima/2I001/TME3/test_csvl)
==4648==    by 0x40078F: main (in /home/omaima/2I001/TME3/test_csvl)
==4648== 
==4648== Invalid read of size 1
==4648==    at 0x4C30F74: strlen (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==4648==    by 0x4EA969B: puts (ioputs.c:35)
==4648==    by 0x400888: display_words_array (in /home/omaima/2I001/TME3/test_csvl)
==4648==    by 0x40079F: main (in /home/omaima/2I001/TME3/test_csvl)
==4648==  Address 0x5204634 is 0 bytes after a block of size 4 alloc'd
==4648==    at 0x4C2FD5F: realloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==4648==    by 0x40097D: decompose_string (in /home/omaima/2I001/TME3/test_csvl)
==4648==    by 0x40078F: main (in /home/omaima/2I001/TME3/test_csvl)
==4648== 
word1
and
word2
and
word3
==4648== 
==4648== HEAP SUMMARY:
==4648==     in use at exit: 8 bytes in 1 blocks
==4648==   total heap usage: 30 allocs, 29 frees, 1,545 bytes allocated
==4648== 
==4648== LEAK SUMMARY:
==4648==    definitely lost: 8 bytes in 1 blocks
==4648==    indirectly lost: 0 bytes in 0 blocks
==4648==      possibly lost: 0 bytes in 0 blocks
==4648==    still reachable: 0 bytes in 0 blocks
==4648==         suppressed: 0 bytes in 0 blocks
==4648== Rerun with --leak-check=full to see details of leaked memory
==4648== 
==4648== For counts of detected and suppressed errors, rerun with: -v
==4648== ERROR SUMMARY: 9 errors from 2 contexts (suppressed: 0 from 0)

Я знаю, что пропавшее свободноеэто функция для температуры в функции, но если я сделаю ее свободной, я потеряю ее значение, необходимое для моего массива.Таким образом, мой вопрос был бы, я могу освободить это, не теряя его ценность?или любое другое решение, гарантирующее как функциональность моей функции, так и устранение любых утечек памяти.Спасибо за ваше время.

Извините, я забыл вот функцию, которую я использовал для освобождения выделенного пространства:

char **destroy_words_array( char** words_array)
{
    int i;
    for(i=0;i<count_words(words_array);i++) free(words_array[i]); //wount_words return the number of elements of the array
    free(words_array);
    return words_array;
}

Ответы [ 2 ]

0 голосов
/ 10 октября 2018

Утечка памяти не там, где вы думаете.Это происходит в начале вашей функции:

char* temp=malloc(sizeof(char*));
char **words_array=malloc((string_words_number(string)+1)*sizeof(char*)); 
for(i=0;i<string_words_number(string);i++)
{   

    temp=NULL;

Вы выделяете место для указателя на temp, но затем перезаписываете этот указатель при входе в цикл for.Удалите этот вызов malloc, и утечка исчезнет.

Однако у вас есть более серьезная проблема: чтение и запись после окончания выделенного буфера.Это происходит здесь:

temp=NULL;
int l=0;
while(string[j]!=' ' && *string)
{   
    temp=realloc(temp,(l+1)*sizeof(char));
    temp[l]=string[j];
    j++;l++;
}
j++;
temp[l]='\0';

Предположим, что в рассматриваемой строке есть два символа для чтения.На первой итерации вашего цикла l равен 0, поэтому вы выделяете l+1 == 1 байт для temp.Затем вы пишете в temp[l] == temp[0], что нормально, затем вы увеличиваете l до 1. На следующей итерации вы выделяете l+1 == 2 байтов для temp, записываете в temp[l] == temp[1] и увеличиваете l до 2Пока все еще хорошо.

Проблема в том, что вы делаете temp[l]='\0'; вне цикла.l теперь равно 2, а размер выделенной памяти равен 2, поэтому вы пишете один элемент за концом массива.

Вам необходимо выделить еще один байт:

j++;
temp=realloc(temp,(l+1)*sizeof(char));
temp[l]='\0';

Обратите также внимание, что вы должны проверять возвращаемое значение malloc и realloc по всему коду в случае его сбоя.

Кроме того, вы неправильно проверяете конец string.Вам нужно сделать:

while(string[j]!=' ' && string[j]!=0)
0 голосов
/ 10 октября 2018

До цикла for у вас есть

char* temp=malloc(sizeof(char*));

, но первое, что находится внутри цикла for, это

temp=NULL;

Так что память, на которую указывает temp, теряется.Если вы запустите эту программу на 64-разрядном компьютере, вы увидите утечку памяти размером 8. Удалите первое объявление temp и измените первую строку цикла for на

char* temp = NULL;

Другойпроблема заключается в состоянии внутреннего цикла while:

while(chaine[j]!=' ' && *chaine)

, поскольку вы не перемещаете указатель chaine, значение *chaine не изменится.Вы, вероятно, хотели написать chaine[j] здесь:

while(chaine[j]!=' ' && chaine[j])

, что эквивалентно

while(chaine[j]!=' ' && chaine[j]!='\0')
...