【问题标题】:How can I free memory in C when a pointer is not known?当指针未知时,如何在 C 中释放内存?
【发布时间】:2014-11-06 21:07:26
【问题描述】:

我希望释放我没有指针的内存块。在我的程序中,我依次调用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);
}

【问题讨论】:

  • 你为什么要像这样在野外 malloc?
  • 为什么?只是为什么?如果您想要连续的内存,请通过一次调用malloc 来分配它并进行一些指针运算。这只会引发未定义的行为。
  • 希望内存分配是连续的似乎相当乐观:)
  • 看来您可能想要一些非常有趣的东西,但没有提供更高级别的细节。更高层次的目标是什么?形成具有更高级别目标和详细信息的帖子可能会满足您的需求。
  • 看来您需要在 C 标准提供的基础上实现自己的内存管理。

标签: c pointers memory memory-management


【解决方案1】:

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

即使您确切地知道malloc() 在做什么,您的程序也会依赖未定义的行为。当新版本的 C 库到来时,行为可能会改变,如果您使用不同的工具链(从 GNU C 切换到 Microsoft C 或其他)编译它,您的程序几乎肯定会失败。

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

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

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

【讨论】:

  • 赞成,但我要补充的是,这不仅仅是你不能这样做,这样做没有意义。 malloc() 说“给我一些内存”,返回值是内存的地址。如果你立即丢弃返回值,那么你就不能使用内存(更不用说释放它了),那么为什么要首先要求它呢?
  • 好吧,这个问题的示例代码很愚蠢,但实际程序似乎正在使用指针做一些事情,而只是懒得跟踪它们。我编写了调用malloc() 的简单程序,而无需费心跟踪内存,因为程序当然会在终止时释放其所有资源。但是我的专业动态程序都跟踪每个分配,我运行 Valgrind 以确保它们永远不会泄漏内存。 stackoverflow.com/a/1529832/166949
【解决方案2】:

free(void*)

[deallocate] 先前通过调用malloccallocrealloc 分配的内存块被释放,使其再次可用于进一步分配。

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

没有办法。

【讨论】:

    【解决方案3】:

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

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

    注意:malloc 的实现会执行“簿记”来确定您要释放的块类型。虽然入侵它们的实现并非不可能,但没有办法以符合标准、可移植的方式进行。

    【讨论】:

      【解决方案4】:

      由于各种原因,您无法创建 [-5]... 事物,但从实际的角度来看,您必须记住分配给 malloc() 的内存来自堆而不是堆栈,因此“从其他地方计算”是很困难的(因为不能保证多次调用 malloc 是连续的)。

      当指针失去与内存的关联(或超出范围)而没有被释放时发生的情况称为内存泄漏,并且没有 C 中不容易使用的详尽技术(例如 Java 的标记/清除垃圾收集,或 mallocing整个内存并扫描它或其他东西)不可能回收此内存。

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

      【讨论】:

        【解决方案5】:

        首先 - 你似乎不明白 malloc 的工作原理 - 将连续数字传递给 malloc不会 使其分配数组。 malloc 定义如下:

        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 函数来释放内存。 free 定义如下:

        void free (void* ptr);
        

        您只需通过以下方式调用它:

        free(myDynamicArray);
        

        【讨论】:

          【解决方案6】:

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

          例如:

          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));
          }
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 2017-03-01
            • 2016-03-06
            • 2016-03-30
            • 1970-01-01
            • 1970-01-01
            • 2011-09-27
            • 2017-05-03
            相关资源
            最近更新 更多