代码之家  ›  专栏  ›  技术社区  ›  Pippi

当指针未知时,如何释放C中的内存?

  •  0
  • Pippi  · 技术社区  · 10 年前

    我希望释放没有指针的内存块。在我的程序中,我调用 malloc 顺序地,希望由 malloc(1) , malloc(4) , malloc(5) 是连续的。然后当我只有指向 malloc(5) 但我想不出这是怎么做到的;我不能简单地创建一个指针来引用ptr[-5]的地址,然后释放5字节的内存?如何做到这一点?

    #include <string.h>
    #include <stdio.h>
    #include <stdlib.h> 
    
    int main(){
    
        malloc(1);
        malloc(4);
        char* ptr = malloc(5);
    
        free(ptr);
    }
    
    6 回复  |  直到 10 年前
        1
  •  7
  •   steveha    10 年前

    不能 做你想做的事。你 甚至不应该尝试 做你想做的事。

    即使你知道 malloc() 如果正在执行,则程序将依赖于未定义的行为。当新版本的C库到来时,这种行为可能会发生变化,如果您使用不同的工具链(从GNU C转换为Microsoft C或其他任何工具)编译它,那么您的程序几乎肯定会失败。

    无论何时分配内存,都需要跟踪指针。如果你的程序甚至不知道内存,就没有办法释放它。

    跟踪内存分配。如果您正在设计动态分配的数据结构,那么您的设计应该包括跟踪它们的功能,例如在链接列表中保留地址列表或其他内容。

    如果这看起来工作量很大,可以考虑使用C#、Java或Python等托管语言。

        2
  •  2
  •   AlexanderBrevig    10 年前

    free(void*)

    [解除分配]以前由调用分配的内存块 malloc , calloc realloc 已解除分配,使其可再次用于进一步分配。

    如果ptr未指向分配有上述函数的内存块,则会导致 未定义的行为 . - http://www.cplusplus.com/reference/cstdlib/free/

    没有办法。

        3
  •  2
  •   Sergey Kalinichenko    10 年前

    但我想不出这是怎么做到的

    这是因为这是不可能的。你从那里回来的街区 malloc 可以以真正任意的顺序出现。释放动态分配的内存块的唯一方法是让程序可以访问指向它的指针。其他都是未定义的行为。

    注: 实施 锦葵属植物 执行“记账”以确定您要释放的区块类型。虽然侵入它们的实现并非不可能,但没有办法以符合标准的、可移植的方式实现。

        4
  •  1
  •   SubSevn    10 年前

    无法创建[-5]。。。但从实际的角度来看,你必须记住分配给你的内存 malloc() 来自堆而不是堆栈,因此很难从其他地方“计数”到它(因为对malloc的多次调用不能保证是连续的)。

    当指针在未释放的情况下失去与内存的关联(或超出范围)时发生的情况称为内存泄漏,如果没有C语言中不易使用的详尽技术(例如Java的标记/清除垃圾收集,或对整个内存进行mallocated并对其进行扫描等),就不可能回收这些内存。

    因此,当指针未知时,无法释放C中的内存。

        5
  •  1
  •   Paweł Stawarz    10 年前

    首先,你似乎不明白 malloc works-将连续数字传递给 锦葵属植物 , 不会 使其分配一个数组。 锦葵属植物 定义如下:

    void* malloc (size_t size);
    

    而整数可以转换为 size_t ,它仍然是分配的字节数,而不是元素数。如果要分配数组,请执行以下操作:

    int* myDynamicArray = malloc(sizeof(int)*numberOfElements);
    

    然后,您可以通过执行以下操作访问元素:

    int i;
    for(i=0;i<numberOfElements;i++)
       printf("%d",myDynamicArray[i]);
    

    然后,正如其他人指出的那样,您可以通过调用 free 作用 自由的 定义如下:

    void free (void* ptr);
    

    你可以这样称呼它:

    free(myDynamicArray);
    
        6
  •  1
  •   Trenin    10 年前

    这绝不是对你所做的事情的认可,但这是可能的 假设您知道这些块是连续分配的 .

    例如:

    int main(){
      char* ptr1=malloc(1);
      char* ptr2=malloc(4);
      char* ptr3=malloc(5);
    
      // Verify that the memory is in fact continuous.
      assert(ptr3==(ptr2+4));
      assert(ptr3==(ptr1+5));
    
      free(ptr3);    // Frees 5 bytes at ptr3
      free(ptr3-4);  // Frees 4 bytes at ptr2
      free(ptr3-5);  // Frees 1 byte at ptr1 
    }
    

    因此,如果你有一个指针,并且知道在它之前分配了一组连续的字节,你可以简单地用指针算术来偏移指针。这是非常危险的,不建议使用,但也有可能。

    编辑:

    我运行了一个测试程序,在我的架构上,它分配了32字节的块,因此ptr1+32==ptr2,ptr2+32=ptr3。它对任何小于或等于24字节的块执行此操作。因此,如果我分配了24个或更少,那么每个ptr将比前一个多32个字节。如果我分配了25个或更多,那么它又分配了16个字节,总共48个字节。

    因此,在我的体系结构中,您需要在如何使用指针算术生成指针方面更具创造性,因为它不会像预期的那样工作。

    下面是一个适用于所有大小的ptr1、ptr2和ptr3的示例程序 关于我的建筑 .

    #define ROUNDUP(number, multiple) (((number + multiple -1)/multiple)*multiple)
    #define OFFSET(size) ((size < 24) ? 32 : ROUNDUP(size+8,16))
    int main(int argc, char* argv[]){
    
      char* ptr1, *ptr2, *ptr3;
      int s1=atoi(argv[1]);
      int s2=atoi(argv[2]);
      int s3=atoi(argv[3]);
      ptr1=(char*)malloc(s1);
      ptr2=(char*)malloc(s2);
      ptr3=(char*)malloc(s3);
    
      fprintf(stdout, "%p %p %p\n", ptr1, ptr2, ptr3);
    
      assert(ptr3==(ptr2+OFFSET(s2)));
      assert(ptr2==(ptr1+OFFSET(s1)));
    
      // Try to construct ptr2 from ptr3.
      free(ptr3);
      free(ptr3-OFFSET(s2));
      free(ptr3-OFFSET(s2)-OFFSET(s1));
    }