【问题标题】:Does free() work on a reassigned pointer?free() 是否适用于重新分配的指针?
【发布时间】:2021-11-03 22:23:57
【问题描述】:

假设我有以下代码:

int *ptr = (int*) malloc(0), *ptr2;
ptr2 = (int*) malloc(4 * sizeof(int));
*(ptr2 + 1) = 3;
ptr = ptr2;
free(ptr)

调用 free(ptr) 是否对 ptr 指向的新内存块起作用或对空指针起作用?

【问题讨论】:

  • 删除了 C++ 标签,因为这里只有 C
  • 仅供参考,malloc(0) 的结果不一定是空指针。根据 C 2018 7.22.3 1,实现定义为选择返回空指针或表现得像 malloc 具有一些非零大小,但返回的指针不得用于访问对象。跨度>
  • 你不应该认为mallocfree是分配或释放指针,即指针类型的对象。指针类型的对象仅保存指针值。 malloc返回一个指针值,你把它存储在什么对象或对象中,与它的操作或free的操作无关。您使用什么对象来获取传递给free 的值是无关紧要的;仅使用传递的指针值。
  • @torstenvl:更正问题中的代码会使 cmets 和答案不一致。请避免修复发布代码的语义,即使它有助于集中问题。

标签: c memory


【解决方案1】:

是的,在您的示例中,ptr 设置为来自mallocptr2

所以,free(ptr); 有效(例如,就像我们做了free(ptr2);)。

但是,现在,我们丢失了 ptr原始 值,所以来自第一个 malloc 的块现在是内存泄漏。也就是说,没有变量具有原始值,因此它永远无法被释放。

要解决这个问题,但保留您的原始代码,我们可以这样做:

int *ptr = (int *) malloc(0), *ptr2;

ptr2 = (int *) malloc(4 * sizeof(int));
*(ptr2 + 1) = 3;

// to prevent a leak of the first malloc ...
int *ptr3 = ptr;

// without ptr3, this would "leak" the original value of ptr
ptr = ptr2;
free(ptr)

// free the first block ...
free(ptr3);

旁注:malloc返回void *,适用于任何指针类型,所以没有需要强制转换返回值.见:Do I cast the result of malloc?

所以,在代码中做(例如):

ptr2 = malloc(4 * sizeof(int));

还有一些额外的代码复制。如果我们更改了 ptr2 的类型,则必须更改 sizeof(int)

所以,为了“面向未来”的代码,很多人更喜欢:

ptr2 = malloc(sizeof(*ptr2) * 4);

更新:

您还可以添加关于 malloc(0) 具有实现定义行为的注释。 – chqrlie

是的,malloc(0) 具有实现定义的行为。一些可能性:

  1. 返回NULL。 IMO,最佳选择
  2. 在内部将分配视为malloc(1)
  3. 返回一个特殊的“零长度”分配。

出于这些原因,我会避免使用malloc(0)。它“脆弱”且具有边际效用。

我 [大部分] 看到新手程序员使用它,他们计划在循环中使用 realloc,并认为他们不能在 NULL 指针上调用 realloc

但是,realloc 将接受 NULL 指针就好了。

例如,如果我们要将一个充满整数的文件读入一个数组,但我们不知道文件中有多少个数字,我们可能会这样做:

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

int
main(int argc,char **argv)
{

    if (argc < 2)
        exit(3);

// NOTE: novices do this ...
#if 0
    int *ptr = malloc(0);
// NOTE: experienced programmers do this ...
#else
    int *ptr = NULL;
#endif

    // number of elements in the array
    size_t count = 0;

    // open the input file
    FILE *input = fopen(argv[1],"r");
    if (input == NULL) {
        perror(argv[1]);
        exit(4);
    }

    while (1) {
        // increase array size
        ptr = realloc(ptr,sizeof(*ptr) * (count + 1));

        // out of memory ...
        if (ptr == NULL) {
            perror("realloc");
            exit(5);
        }

        // decode one number from file
        if (fscanf(input,"%d",&ptr[count]) != 1)
            break;

        // advance the count
        ++count;
    }

    // close the input stream
    fclose(input);

    // trim array to actual size used
    ptr = realloc(ptr,sizeof(*ptr) * count);

    // print the array
    for (size_t idx = 0;  idx < count;  ++idx)
        printf("%zu: %d\n",idx,ptr[idx]);

    // free the array
    free(ptr);

    return 0;
}

注意:在一些特殊情况下,malloc(0)确实有意义。通常,必须将指针传递给一些代码,这些代码将辨别NULLmalloc(0) 与常规分配。但是,它们是一种高级用法,我不建议初学者使用它们。

【讨论】:

    【解决方案2】:

    free(ptr) 将释放 ptr2 指向的四个“int”。更改未分配的内存不会使其分配。

    我会警告你这里有内存泄漏。 ptr 最初指向的内存仍将被分配但未被引用。

    【讨论】:

    • ptr 最初指向的内存仍然是未分配但未被引用的。 更准确地说:ptr 最初指向的内存,如果有的话,仍然会被分配,但是无法访问。
    • 谢谢@chqrlie
    猜你喜欢
    • 2012-12-02
    • 2020-02-10
    • 1970-01-01
    • 2015-07-14
    • 1970-01-01
    • 2013-01-07
    • 1970-01-01
    • 2021-05-13
    • 2010-09-22
    相关资源
    最近更新 更多