【问题标题】:Mysterious behavior of malloc() function in CC中 malloc() 函数的神秘行为
【发布时间】:2020-07-04 20:22:52
【问题描述】:

在下面的代码中,有两个 int 数组被分配到另一个函数中(我想检查我是否可以释放任何指针,或者只能释放本地分配的指针)。两个数组都以某种方式链接,我不明白为什么?

#include <stdlib.h>
#define LEN 10

int* foo(int*, int);
void main()
{
    int* arr = (int*)malloc(sizeof(int) * LEN);
    int* arr2 = foo(arr, LEN);
    for (int i = 0; i < LEN; i++)
    {
        arr2[i] = i;
        printf("%d\t", arr2[i]);
    }
    printf("\n");
    for (int i = 0; i < LEN; i++)
    {
        printf("%d\t", arr[i]);
    }
    printf("\n");

    for (int i = 0; i < LEN; i++)
    {
        arr[i] = i+1;
        printf("%d\t", arr[i]);
    }
    printf("\n");

    for (int i = 0; i < LEN; i++)
    {
        printf("%d\t", arr2[i]);
    }
    free(arr2);
}

int* foo(int* arr, int n)
{
    free(arr);
    return (int*)malloc(sizeof(int) * n);
}

输出是:

0       1       2       3       4       5       6       7       8       9
0       1       2       3       4       5       6       7       8       9
1       2       3       4       5       6       7       8       9       10
1       2       3       4       5       6       7       8       9       10

【问题讨论】:

  • 在调用foo(arr, LEN); 之后,arr 是一个悬空指针,使用它会表现出未定义的行为。实际上,malloc 重用最近释放的块是完全正常且不足为奇的。
  • @JohnBollinger: free 可以应用于malloc 系列中的例程返回的任何指针值(并且自释放后)或空指针。该行为未定义为将其应用于自动对象、静态对象等的地址。

标签: c pointers malloc free


【解决方案1】:

调用foo后,arr指向的内存已经被释放。然后您尝试访问arr 指向的内存。

在内存被释放后尝试使用它会调用undefined behavior

先尝试只使用arr,然后调用foo,再使用arr2

【讨论】:

    【解决方案2】:

    mallocfree 不分配和释放指针。它们分配和释放空间(数据存储区域)。

    该空间由地址(指针值)引用。调用malloc并将其返回值赋给arr后,arr指向预留空间。当您将该指针值传递给foo 并且foo 将其传递给free 时,空间不再保留。

    当您在foo 中调用malloc 时,它会再次保留空间。它可以保留相同的空间、重叠的空间或不同的空间。当您将第二次调用中返回的值用作指针时,它会访问当前保留的空间。

    当您访问arr 中的剩余值时,您的程序访问了之前保留的空间。 (情况并非总是如此;一旦释放了空间,您就不应再使用旧指针。C 实现并不总是将旧指针视为有效,您的程序可能会崩溃,使用旧空间,使用不同的空间,或表现出其他行为。)

    arrarr2 的声明位置以及 mallocfree 的调用位置无关紧要 - 用于保存地址值的 指针 的范围与空间的保留。指针的 提供对空间的访问。无论您通过例程调用向上还是向下传递一个值,它仍然指向同一个空间。

    【讨论】:

      【解决方案3】:

      你的代码遇到错误,如果你想让事情正常工作,你应该注意修复它们:

      int* arr = (int*)malloc(sizeof(int) * LEN);
      

      调用 malloc 而不检查返回值!

      if(!arr){
          puts("heap allocation failure");
          abort();
      }
      

      在函数 foo 中:

      return (int*)malloc(sizeof(int) * n);
      

      同样的问题!检查 malloc 返回。 从这个函数返回后,main 中的 arr 指针指向释放的缓冲区!!

      在这一行:

      printf("%d\t", arr[i]);
      

      访问悬空指针,指针已被 foo 释放!这段记忆不是你的。这将导致sigmentation错误!如果您没有收到 SIGSIGV 信号,则为未定义的行为。

      【讨论】:

        【解决方案4】:

        这里 arr 和 arr2 都指向同一个内存位置。

        【讨论】: