【问题标题】: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(); 时都会在 global_base(链表)的尾部添加一个新项目。 但是,当我尝试通过调用 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_metamymalloc 返回时已超出范围,但您将此地址保存为global_base,并在后续调用mymallocprintList 时继续尝试使用该地址。

标签: c linked-list infinite-loop singly-linked-list


【解决方案1】:

您的方法存在多个问题:

  • meta_data block_meta; 是一个局部变量。您不能使用它来链接块。局部变量在函数退出时被回收。你应该使用从系统中检索到的全局内存,sbrk,由pointer 指向。

  • 打印循环不正确:您应该写while (node != NULL) 来打印所有块。

【讨论】:

    【解决方案2】:

    你的代码有很多我会解决的问题。

    1. 现在代码的问题,实际上最大的问题是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;
    }
    
    1. 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;
    }
    

    【讨论】:

      猜你喜欢
      • 2013-03-19
      • 1970-01-01
      • 2018-11-23
      • 2017-09-03
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多