链表遍历无限
Posted
技术标签:
【中文标题】链表遍历无限【英文标题】:linked list traversal goes infinitely 【发布时间】:2022-01-06 17:37:34 【问题描述】:我正在尝试在 c 中实现我自己版本的 malloc() 函数。 我决定使用元数据对象的链接列表来跟踪我分配的块,该链接列表将存储有关已分配块的一些信息并将其放置在块之前。 现在长话短说,在调试时我发现我的链表表现得非常奇怪。 这里有一段代码可以帮助理解问题。
typedef struct meta_data
size_t size;
int free;
struct meta_data* next;
meta_data;
meta_data* global_base;
void *mymalloc(size_t size)
if(size > 0)
meta_data block_meta;
void* pointer = sbrk(size + block_size);
block_meta.size = size;
block_meta.next = NULL;
block_meta.free = 0;
if(!global_base) //first allocation
global_base = &block_meta;
else
block_meta.next = global_base;
return pointer;
else
return NULL;
我编写了这段代码,我假设每次调用 mymalloc(
void printList()
meta_data * node = global_base;
while (node->next != NULL)
printf("%zu", node->size);
printf(" -> ");
node = node->next;
printf(" \n ");
int main()
mymalloc(10);
mymalloc(8);
mymalloc(4);
printList();
return 0;
我希望我的输出是
10 -> 8 -> 4
但它是 4 -> 4 -> 4 -> 4 -> 4 .....
并进入无限循环
知道这段代码哪里出错了。
我对使用 C 编程有点陌生,所以我唯一的猜测是我不正确地使用了引用 &
和指针 *
。
此外,我还看到过使用->
来分配结构属性的代码,但我只能使用.
来实现(无论如何这可能是问题所在)?
感谢大家的帮助
【问题讨论】:
您正在为初学者打印list->size
,而不是node->size
。而且我在任何地方都没有看到list
的定义
所以请不要键入。复制并粘贴正确的minimal reproducible example。
你为什么使用sbrk
?这似乎有点复杂。你不能在幕后使用 malloc 吗?
@jarmod OP 正在尝试实施 malloc
。
block_meta
在mymalloc
返回时已超出范围,但您将此地址保存为global_base
,并在后续调用mymalloc
和printList
时继续尝试使用该地址。
【参考方案1】:
您的方法存在多个问题:
meta_data block_meta;
是一个局部变量。您不能使用它来链接块。局部变量在函数退出时被回收。你应该使用从系统中检索到的全局内存,sbrk
,由pointer
指向。
打印循环不正确:您应该写while (node != NULL)
来打印所有块。
【讨论】:
【参考方案2】:你的代码有很多我会解决的问题。
-
现在代码的问题,实际上最大的问题是
myalloc
函数没有创建新的block_meta
节点。它只是声明了一个block_meta
变量(最终会出现在堆栈上,更糟糕的是,它会导致灾难性的错误,我相信无限循环是由此造成的)。在执行类似操作之前,您应该使用sbrk
函数创建meta_data
节点:
...
meta_data *block_meta = sbrk(sizeof(meta_data));
block_meta->size = size;
block_meta->next = NULL;
block_meta->free = 0;
if(!global_base)
global_base = block_meta;
myalloc
函数检查global_base
是否已分配,即链表中是否存在根节点。如果有的话,它应该简单地告诉当前变量将自己链接到global_base
,即next
变量在global_base
,这是一个很大的错误。首先,global_base
是根节点,告诉当前节点将自己链接到链表的根是没有意义的,它应该将自己链接到下一个节点而不是根。其次,对前一个节点的引用丢失了,这意味着它不再是一个链表。一个适当的解决方案是使用static
变量将当前节点保存在一个变量中,以防止它在myalloc
函数退出时丢失:
...
static meta_data *curr;
然后在返回指向新分配块的指针之前,添加这一行来保存新创建的节点:
...
curr = block_meta;
return pointer;
现在返回错误的 else 语句并将其更改为确保前一个节点指向当前节点:
...
else
curr->next = block_meta;
【讨论】:
以上是关于链表遍历无限的主要内容,如果未能解决你的问题,请参考以下文章