Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/61.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C 数据结构实现能否知道它是否在堆上?_C_Malloc_Free_Heap Memory - Fatal编程技术网

C 数据结构实现能否知道它是否在堆上?

C 数据结构实现能否知道它是否在堆上?,c,malloc,free,heap-memory,C,Malloc,Free,Heap Memory,考虑一个主文件和另一个实现数据结构的文件,比如:链表 链表的调用者可以将对象放在堆栈或堆的链表上,我认为这是调用者的责任 所以,在实现链表时,它如何知道它是否在堆上?考虑一个从列表中移除节点的典型方法。链表如何知道它是否应该释放内存?根据我的理解,释放堆栈上的某些内容会导致未定义的行为 因为这是类项目的一部分,所以我无法传递一些isOnHeap来指示调用方是否已将内存放在堆上:无法,因为在我们的实现中不允许这样做,所以我假设这个问题可能有一个通用的解决方案,特别是考虑到这种情况有多常见。请注意,

考虑一个主文件和另一个实现数据结构的文件,比如:链表

链表的调用者可以将对象放在堆栈或堆的链表上,我认为这是调用者的责任

所以,在实现链表时,它如何知道它是否在堆上?考虑一个从列表中移除节点的典型方法。链表如何知道它是否应该释放内存?根据我的理解,释放堆栈上的某些内容会导致未定义的行为


因为这是类项目的一部分,所以我无法传递一些isOnHeap来指示调用方是否已将内存放在堆上:无法,因为在我们的实现中不允许这样做,所以我假设这个问题可能有一个通用的解决方案,特别是考虑到这种情况有多常见。请注意,链表实现必须处理其自身内存的释放(假定这是给定的),因为其实现对调用者是隐藏的。

C中的数据结构实现不应释放任何内容,除非明确告知它这样做。典型的链表实现可能具有创建节点、在此处将节点插入列表、从列表中删除节点和销毁节点等功能。这些都不需要检查堆栈和堆。通常,堆栈上唯一的东西是整个列表的头和尾指针;即使如此,您也可以通过设计和使用堆来分配和释放API函数

如果你真的想建立一个侵入式的链表,在这个链表中节点可以保存在堆栈上,我们也可以讨论这个问题,但是考虑到你发布的背景,我怀疑这是不是真的

无论如何,没有可移植的解决方案可以知道堆栈或堆上是否有某些东西,但是这里有一些特定于平台的技巧:-注意,对于类赋值,您不太可能需要这些技巧

。。。我无法传递isOnHeap来指示调用方是否已将内存放入堆中

这种情况偶尔会出现,但实际上并非如此。由于运行库的版本不同,问题通常会迎头出现。问题是库分配了调用者必须释放的块

这个问题的一个例子可以在WindowsNETAPI函数中看到。例如,假设您调用枚举组。库将分配组信息结构。调用者完成结构后,调用者有责任调用库的

在这种情况下,项目需要提供分配器和删除器函数。然后你的例程简单地分配给其他人提供的例程;然后在不再需要对象时使用例程删除


为了解决最初的问题,通常可以梳理出分配是在哪里进行的。但是堆栈与堆通常并不重要。

通常,链表节点是动态创建的,并将在堆中分配。但是,如果选择将已在堆栈上的节点放入列表,则将违反此假设。我想你是在问这种情况


然后,根据库的实现,free可能什么都不做,只要注册内存,使其在堆中可用即可。如果内存恰好在堆栈中,它可以选择执行任何操作。或者它可能会给出一个错误并退出。但是它是未定义的。

这里有一个简单的是关于stackaddr函数的:

int *stack_start = nullptr;

bool is_on_stack(void* ptr) {
  int stack_probe;  
  if( stack_start < &stack_probe  )
    return stack_start < ptr && ptr < &stack_probe; // stack grows upwards;
  else 
    return &stack_probe < ptr && ptr < stack_start; // stack grows downwards;
}

int main() {
  int stack_probe = 0;
  stack_start = &stack_probe;

  int dummy;

  bool r1 = is_on_stack(&dummy); // shall be true

  int* heap_thing = (int*)malloc(sizeof(int));

  bool r2 = is_on_stack(heap_thing); // shall be false         
}

如果这对数据结构代码很重要,但是为什么呢?那么应该从头设计到API中。标签表明这是一个与C相关的问题,并将C添加到标题中。我确实看到了这个问题。但是,请考虑问题的背景,通常是的。但有时使用堆栈上的数据更有效。在某些情况下,同一个列表可能会混合使用堆上和堆栈上的项。通常项知道如何销毁它自己,它引用了销毁函数或其他类似的函数…我有点困惑,因为我们学习的释放内存的典型示例是确保链表结构迭代并释放所有分配的内存。如果列表实现对调用方隐藏,那么调用方如何知道如何释放堆上已分配的节点上的任何数据?我不是在挑战你的观点,顺便说一句,这是一个真正的问题。打电话的人应该承担责任,这对我来说更有意义。然而,我们列表实现中给定的remove和destroy函数指示释放动态内存。谢谢,但我找到了一个可能的替代解决方案-因此我将重新询问一些更具体的问题。由于这在技术上回答了这个问题,我将选择它作为anyon的答案
我想你的代码中有一个错误。在is_on_stack中,将stack_probe分配为int,然后将其未定义的内容与stack_start(int指针)进行比较。这显然是错误的。我认为您希望在该函数的所有测试中使用&stack_probe而不是stack_probe。此外,如果我错了,请纠正我,我相信这是C规范中未定义的行为。您正在比较指向不同对象的指针。虽然我同意这应该适用于大多数C实现,但我觉得我需要指出这一点。@DoxyLover,同意你的观点。解决方案可能在某些实现中不起作用,例如某些处理器、Big-Endian、堆栈的增长方向、多线程…,@DoxyLover,谢谢,已修复
  int stack_probe = 0;
  stack_start = &stack_probe;