如何释放分配的内存而不丢失其值

时间:2018-10-10 15:01:51

标签: c valgrind free

您好,我用C语言编写了此函数,该函数使用一串单词并返回一个二维char数组,每种情况都以正确的顺序初始化为一个单词,我编译并完成了分配的任务

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)

我知道缺少的空闲空间是该函数中temp的空闲空间,但是如果我释放它,最终将失去它对数组所需的值。所以我的问题是,我可以释放它而不损失它的价值吗?或任何其他保证我功能的功能以及擦除所有内存泄漏的解决方案。谢谢您的宝贵时间。

对不起,我忘记了我用来释放分配的空间的功能:

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 :(得分:1)

内存泄漏不在您认为的位置。它发生在您的功能开始时:

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个字节,写入了{{1 }},并将temp[l] == temp[1]增至2。到目前为止,效果还不错。

问题在于您在循环外执行ltemp[l]='\0';现在为2,分配的内存大小为2,因此您要在数组末尾写入一个元素。

您需要在此处再分配一个字节:

l

还请注意,如果代码失败,则应在整个代码中检查j++; temp=realloc(temp,(l+1)*sizeof(char)); temp[l]='\0'; malloc的返回值。

此外,您没有正确检查realloc的结尾。您需要这样做:

string

答案 1 :(得分:0)

在进行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')