C链接列表添加和删除

时间:2013-04-01 23:07:10

标签: c

typedef struct _readyQ {
    pcb_t *pcb;
    struct _readyQ  *next;
} readyQ;

static readyQ *ready_queue_head = NULL, *ready_queue_tail = NULL;
static void submit_ready_request(pcb_t *pcb);

static void submit_ready_request(pcb_t *pcb)
{
    readyQ *r;
    /* Build I/O Request */
    r = malloc(sizeof(readyQ));
    assert(r != NULL);
    r->pcb = pcb;
    r->next = NULL;

    pthread_mutex_lock(&readyQ_mutex);
    /* Add request to head of queue */
    if (ready_queue_tail != NULL)
    {
        ready_queue_tail->next = r;
        ready_queue_tail = r;
    }
    else
    {
        ready_queue_head = r;
        ready_queue_tail = r;
    }
    pthread_mutex_unlock(&readyQ_mutex);
}

最初head / tail都是NULL。 所以,当我第一次通过submit_ready_request添加时,我将转到其他部分

ready_queue_head = r;
ready_queue_tail = r;

都指向同一个readyQ r。

现在当我添加另一个时,它将转到

ready_queue_tail->next = r;
ready_queue_tail = r;

我想知道这个案子, 执行上面的代码后,ready_queue_head->next将指向r?

因为我试图通过此删除,但它无法正常工作

readyQ *r;
r = malloc(sizeof(readyQ));
if (ready_queue_head != NULL) {   //not empty so remove
       r = ready_queue_head;  
       if(ready_queue_head->next != NULL){   
          ready_queue_head = ready_queue_head->next; 
        } else {    //only one in the queue
          ready_queue_head = NULL;
          ready_queue_tail = NULL;
       }
}

4 个答案:

答案 0 :(得分:2)

我怀疑当你说它不起作用时,你的意思是在“删除”两个节点后r不为空。如果是这样,则错误是删除代码中的此分配:

r = malloc(sizeof(readyQ));

如果列表为空,那将是结果(可能不需要)。如果列表不为空,那么该内存会立即泄露。应该只是:

r = NULL;

答案 1 :(得分:1)

我没有看到任何错误(除了虚假的malloc),所以编译你的代码并没有得到任何段错误或其他错误。我唯一改变的就是删除互斥锁。可能是故障发生在互斥体中?您的出队代码是否受互斥锁保护?

另外,回答关于ready_queue_head->的问题,接下来是的,它会按预期工作。实际上,您可以将出队代码简化为:

r = ready_queue_head;  
ready_queue_head = ready_queue_head->next; 
if (ready_queue_head == NULL){   
    ready_queue_tail = NULL;
}

答案 2 :(得分:1)

首先,弹出操作不需要malloc()。其次,你的推动和流行都过于迂腐。仔细盯着这个推送和弹出逻辑非常,并且在知道它是如何工作之前不要合并它。您需要考虑两个如何协同工作以真正掌握简单性。

首先推送逻辑。以下假设r是新分配的节点,其下一个指针为NULL

if (ready_queue_head != NULL)
    ready_queue_tail->next = r;
else
    ready_queue_head = r;
ready_queue_tail = r;

同样,pop-logic

r = ready_queue_head;
if (r != NULL) 
   ready_queue_head = r->next

考虑一下你头脑中的一些测试用例。

推送逻辑

  • 在空列表中插入新节点时会发生什么?由于列表为空,头指针将为NULL,因此头指针和尾指针都将最终引用新节点。
  • 如何插入包含一个元素的列表?由于头指针是非空的,因此必须还有一个有效的尾指针,因此将其下一个指针设置为新节点,然后设置指向新节点的尾指针。
  • 如果插入前列表中有多个节点,是否会改变?完全没有。

Pop Logic

  • 从空队列请求弹出时会发生什么?由于空指针上的头指针为NULL,因此返回值r也将为NULL。
  • 从单元素队列请求弹出时会发生什么?头指针引用单个元素,因此r将被正确设置。由于r非空,因此头指针前进到其next指针,该指针将为NULL。该列表现在为空(head为NULL)并且设置了返回节点指针。
  • 具有多个节点的列表怎么样?单节点弹出中的所有内容都适用,但是退出时头指针不会为NULL,因此列表仍然不为空(但 比以前短一个元素。再次,返回节点指针r已正确设置。

无论如何,我希望它有所帮助。很难理解尾部指针在所有这些中的参与程度有多少,但是在你考虑它一段时间之后并不是很好。作为奖励,这是一个过于复杂的空洞逻辑。

return (ready_queue_head != NULL);

答案 3 :(得分:-1)

r = malloc(sizeof(readyQ));

以上语句不会为结构分配内存。相反,它将为指向结构的指针分配内存。