【问题标题】:Will returning an array from a function cause a memory leak?从函数返回数组会导致内存泄漏吗?
【发布时间】:2019-02-25 12:28:38
【问题描述】:

由于我们无法释放函数中定义的本地指针“tmparr”,会不会导致内存泄漏?不确定这里是否有更好的编码解决方案。

我正在尝试将指针传递给函数,以便它也可以处理和更改函数内部的数据。数据的大小和值可以在函数内灵活修改。

void printArray(int* data, 
                int length)
{
    for (int i=0; i<length; i++) {

        if ((i>0) && (i%5==0))
            printf("\n");

        printf("%d ", data[i]);
    }

    printf("\n\n");

}

void copyPassPtrArray(int** data,
                      int length)
{
    int* tmparr = (int*)malloc(length * sizeof(int));

    for (int i=0; i<length; i++)
        tmparr[i] = i + 10;

    *data = tmparr;
}


int main()
{
    int length = 10;

    int* ptrarr = (int*)malloc(length * sizeof(int));

    for (int i =0; i <length; i++)
        ptrarr[i] = i;

    printf("Origin ... \n");
    printArray(ptrarr, length);

    copyPassPtrArray(&ptrarr, 20);
    printf("After copyPassPtrArray ... \n");
    printArray(ptrarr, 20);

    free(ptrarr);

    return 0;
}

看完cmets后,我有以下建议的api解决方案。这种做法的目的是我们可能不知道在函数中进行某些计算后数组和值的大小。它的“数据”需要返回到主函数或其他函数。但是,是否还有内存泄漏?

void copyGlobalPtrArray(int** data,
                        int length)
{   
    *data = (int*)malloc(length * sizeof(int));

    for (int i=0; i<length; i++)
        (*data)[i] = i + 10;
}

【问题讨论】:

  • 你为ptrarr分配了两次内存,只释放了一次;所以是的,这将导致内存泄漏。 (您也可以尝试并测量它,例如使用 valgrind)。
  • 如果你在一个函数中分配的内存没有在该函数中释放(通常不推荐),返回从函数中的数据,所以您在函数调用时有一个明确的值要分配给它。这样可以更清楚地释放哪些变量。
  • 太棒了。您的反馈确实启发了我。谢谢。

标签: c arrays pointers


【解决方案1】:

是的,有泄漏。 但它不是你想的那样。

您正确地free'd 分配在copyPassPtrArray 中的区域。 但是,原来分配的指针,

int* ptrarr = (int*)malloc(length * sizeof(int));

尚未被释放。 那是因为您在行中重写了原始数据的指针

copyPassPtrArray(&ptrarr, 20);

旧指针永远丢失了! 相反,您应该存储到一个新指针中,并在最后释放两个指针。

例如

int main()
{
    int length = 10;

    int* ptrarr = (int*)malloc(length * sizeof(int);
    int* copyarr;

    for (int i =0; i <length; i++)
        ptrarr[i] = i;

    printf("Origin ... \n");
    printArray(ptrarr, length);

    copyPassPtrArray(&copyarr, 20);     // put copied pointer into a separate variable
    printf("After copyPassPtrArray ... \n");
    printArray(copyarr, 20);

    free(ptrarr);
    free(copyarr);
    return 0;
}

【讨论】:

  • 谢谢。将“ptrarr”传递给函数的目的,该函数可能需要引用值的数组进行计算,同时它可能会在函数本身中重写值并调整数组的大小。最后,该函数重用内存缓冲区并返回到主函数或其他函数。
【解决方案2】:

如果你不太确定你是否编写了没有内存泄漏问题的代码,那么使用内存泄漏工具是一个好习惯

valgrind 是可以使用的工具之一。

下面是命令:

valgrind --tool=memcheck --leak-check=full  ./memleak  (program name)
==422== Command: ./memleak
Origin ... 
0 1 2 3 4 
5 6 7 8 9 
After copyPassPtrArray ...
10 11 12 13 14 
15 16 17 18 19 
20 21 22 23 24 
25 26 27 28 29 

==422== HEAP SUMMARY:
==422==     in use at exit: 40 bytes in 1 blocks
==422==   total heap usage: 2 allocs, 1 frees, 120 bytes allocated  // here total allocations n free done  in ur code

==422== 40 bytes in 1 blocks are definitely lost in loss record 1 of 1
==422==    at 0x4C2AB80: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==422==    by 0x400767: main (memleak.c:35)    //shows line number 

==422== LEAK SUMMARY:
==422==    definitely lost: 40 bytes in 1 blocks  // here u can see memory leak
==422==    indirectly lost: 0 bytes in 0 block
==422==      possibly lost: 0 bytes in 0 blocks
==422==    still reachable: 0 bytes in 0 blocks
==422==         suppressed: 0 bytes in 0 blocks

==422== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)

所以最好运行它并尝试自己解决内存泄漏

【讨论】:

  • 注明。我听说过“valgrind”,将安装并试用。谢谢你教我——“如何钓鱼”。赞赏。
【解决方案3】:

通常,在同一函数内部未释放的函数内部分配内存并不是一个好主意。更好的是,为函数外部的变量分配内存,将变量传递给函数,同时释放函数外部的变量。

类似这样的:

void copyPassPtrArray(int *tmparr, int length)
{
    for (int i=0; i<length; i++)
        tmparr[i] = i + 10;
}


int main()
{
    int length = 10;
    int doublelength = 2 * length;

    int* ptrarr = (int*)malloc(length * sizeof(int));
    int* newarr = (int*)malloc(doublelength * sizeof(int));

    for (int i =0; i <length; i++)
        ptrarr[i] = i;

    ...

    copyPassPtrArray(newarr, doublelength);

    ...

    free(newarr);
    free(ptrarr);

    return 0;
}

如果你想在函数内部分配内存,显式地在一个变量中返回该内存,并将它分配给一个(新的)变量。

那么你的代码可能是这样的:

int *copyPassPtrArray(int length)
{
    int* tmparr = (int*)malloc(length * sizeof(int));

    for (int i=0; i<length; i++)
        tmparr[i] = i + 10;

    return tmparr;
}


int main()
{
    int length = 10;

    int* ptrarr = (int*)malloc(length * sizeof(int));
    int* newarr = NULL;

    for (int i =0; i <length; i++)
        ptrarr[i] = i;

    ...

    newarr = copyPassPtrArray(20);

    ...

    free(newarr)
    free(ptrarr);

    return 0;
}

如果您现在改为使用 ptrarr = copyPassPtrArray(20); 行,您会更容易注意到您正在覆盖/重新分配 ptrarr,因为它与之前的分配位于同一块中。

【讨论】:

  • 如果函数的任务是分配内存供函数外使用,则不必在函数内部释放分配的内存。但是如果函数不需要返回额外分配的内存,那么它确实负责释放它分配的内存。
猜你喜欢
  • 2023-03-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-06-18
  • 2021-03-23
  • 2021-09-25
  • 2014-12-08
  • 1970-01-01
相关资源
最近更新 更多