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

当指针未知时,如何在C中释放内存?,c,pointers,memory,memory-management,C,Pointers,Memory,Memory Management,我希望释放没有指针的内存块。在我的程序中,我依次调用malloc,希望由malloc(1),malloc(4),malloc(5)创建的内存是连续的。然后,当我只有指向malloc(5)的指针时,释放这些内存。但我想不出怎么能做到这一点;我不能简单地创建一个指向ptr[-5]地址的指针,然后释放5字节的内存?如何做到这一点 #include <string.h> #include <stdio.h> #include <stdlib.h> int main

我希望释放没有指针的内存块。在我的程序中,我依次调用
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);
}
#包括
#包括
#包括
int main(){
malloc(1);
malloc(4);
char*ptr=malloc(5);
免费(ptr);
}
免费(无效*)

[解除分配]先前通过调用
malloc
calloc
realloc
分配的内存块被解除分配,使其再次可用于进一步分配

如果ptr未指向与上述函数一起分配的内存块,则会导致未定义的行为。 -

没有办法

但我想不出怎么能做到这一点

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


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

由于各种原因,您无法创建[-5]…东西,但从实际角度来看,您必须记住,分配给
malloc()
的内存是从堆中出来的,而不是从堆栈中出来的从其他地方对它进行“计数”是困难的(因为对malloc的多次调用不能保证是连续的)

如果指针在未被释放的情况下失去与内存的关联(或超出范围),则称为内存泄漏,如果没有C语言中不可用的穷举技术(例如Java的标记/清除垃圾收集,或对整个内存进行mallocing并扫描它或其他),则无法回收该内存


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

这绝不是对您所做工作的认可,但如果您知道块是连续分配的,则有可能

#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));
}
例如:

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));
}
#定义汇总(数字,倍数)(((数字+倍数-1)/倍数)*倍数)
#定义偏移量(大小)((大小<24)?32:汇总(大小+8,16))
int main(int argc,char*argv[]){
字符*ptr1,*ptr2,*ptr3;
ints1=atoi(argv[1]);
int s2=atoi(argv[2]);
ints3=atoi(argv[3]);
ptr1=(char*)malloc(s1);
ptr2=(char*)malloc(s2);
ptr3=(char*)malloc(s3);
fprintf(标准输出,“%p%p%p\n”、ptr1、ptr2、ptr3);
断言(ptr3==(ptr2+偏移量(s2));
断言(ptr2==(ptr1+OFFSET(s1));
//尝试从ptr3构造ptr2。
免费(ptr3);
自由(ptr3偏移量(s2));
自由(ptr3偏移(s2)-偏移(s1));
}
你不能做你想做的事。你甚至不应该尝试做你想做的事

即使您准确地计算出malloc()在做什么,您的程序也将依赖于未定义的行为。当新版本的C库出现时,行为可能会发生变化,如果您使用不同的工具链编译程序(从GNU C切换到Microsoft C或其他任何工具),您的程序几乎肯定会失败

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

跟踪内存分配。如果要设计动态分配的数据结构,则设计应包括跟踪这些结构的功能,例如在链接列表中保留地址列表或其他内容


如果这看起来是一个很大的工作,也许考虑使用像C语言或java或Python之类的托管语言。首先,你似乎不理解<代码> MalOC/<代码>如何工作。将连续的数字传递给<代码> MalOC/,<强>不会< /强>使它分配一个数组。<代码> MalOC 定义如下:

void* malloc (size_t size);
int* myDynamicArray = malloc(sizeof(int)*numberOfElements);
void free (void* ptr);
虽然整数可以转换为
大小\u t
,但它仍然是分配的字节数,而不是元素数。如果要分配数组,请按如下操作:

void* malloc (size_t size);
int* myDynamicArray = malloc(sizeof(int)*numberOfElements);
void free (void* ptr);
然后,您可以通过执行以下操作来访问元素:

int i;
for(i=0;i<numberOfElements;i++)
   printf("%d",myDynamicArray[i]);
free(myDynamicArray);
你可以简单地称之为:

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

为什么你要在野外这样进行malloc呢?为什么?为什么?如果你想要连续的内存,只需调用
malloc
并执行一些指针运算就可以分配它。这只会导致未定义的行为。希望内存分配是连续的似乎很乐观:)看起来你可能想要一些这里的事情很有趣,但是