【问题标题】:Delete node from singly linked list and do an operation on it从单链表中删除节点并对其进行操作
【发布时间】:2022-01-05 23:54:08
【问题描述】:

我的任务是从单链表中删除一个节点,并将该节点的 dataPtr 指向的结构设置为一个新值。我创建了一个结构指针来保存弹出节点的数据。有两种情况我想捕捉 1) 这个新指针为空,我想将它设置为弹出的节点 2) 如果指针不为空,我想对其进行一些操作。

NODE* printer;
printer = (NODE*) malloc(sizeof (NODE));   //dynamically allocate
if(printer==NULL){                  //if it has no data
    printer= deleteNode(sList);     //call deleteNode function which returns popped node from the passed singly linked list   
} else if (printer!=NULL && sList->count!=0) {       //if it has data
    (((PRINTJOB *) printer->dataPtr)->pageNums) -= PAGESPERMINUTE;    //decrement the pageNums field by 1 (PAGESPERMINUTE)
    if ((((PRINTJOB *) printer->dataPtr)->pageNums) <= 0) {      //if the field is less than 0
        printer = NULL;   //set pointer back to null
    }
    printf("printers pageNum is: %d\n", ((PRINTJOB *) printer->dataPtr)->pageNums);
}

我的编译器在第 4 行给我一个错误:该值从未使用过。 它还在我的 else if 语句中给了我一个错误:第一个条件始终为真。 当我也运行此代码块时,它会使我的程序崩溃。

我的deleteNode函数是:

#include "headers.h"
void* deleteNode(LIST* list){
    NODE *toDelete;
    toDelete = list->head;
    list->head = toDelete->next;
    return toDelete;
}

我的节点结构是:

typedef struct node{ 
    void* dataPtr;
    struct node* next;
} NODE;

【问题讨论】:

  • 你不需要测试printer!=NULL,如果它恰好是NULL,它只会得到它
  • 代码没有多大意义。您正在为新节点分配未初始化的内存。如果分配失败,则调用deleteNode 函数将最前面的项目从列表中弹出。如果分配成功,您将开始尝试访问此未初始化节点中的内容,这将导致未定义的行为。如果这没有崩溃,那么您有可能最终将指针设置为 NULL,这会泄漏内存,然后您的 printf 调用将在您执行 NULL 取消引用后崩溃。
  • 你的删除函数有一个bug,当你从函数返回时你没有改变列表的头部
  • 我的删除功能有什么错误?
  • @vmp 这是不必要的。可以将列表作为指针传递。那不是错误。如果有的话,应该鼓励 OP简化他们对指针的使用,因为他们显然难以理解如何使用它们。

标签: c linked-list dynamic-memory-allocation singly-linked-list


【解决方案1】:

我的任务是从单链表中删除一个节点,并将该节点的 dataPtr 指向的结构设置为一个新值。

但是您只能有条件地删除节点(并且在不太可能实际发生的条件下)。如前所述,如果第一步是删除节点,则删除。那。节点。

我创建了一个结构指针来保存弹出节点的数据。

但你不应该。如果有任何数据可以接收,那是因为包含它的节点已经存在,而您的 deleteNode() 函数将返回一个指向它的指针(前提是该函数实际上已被调用)。

我想捕捉 2 种情况 1)其中这个新指针为空,我想将它设置为弹出节点

这没有意义,因为首先创建一个新的、单独的节点是没有意义的。 有意义的是检查deleteNode 是否返回一个空指针,可以想象如果列表为空,它可能会这样做(但见下文)。

  1. 如果指针不为空,我想对它做一些操作。

这可能是有道理的,但不是在这种情况下。根据您的描述,您希望对从列表中删除的节点执行操作(前提是实际上已删除),但您正在处理新分配的未初始化节点。

仅根据您对任务本身的描述,听起来您想要更像这样的东西:

NODE* printer = deleteNode(sList);
if (printer != NULL) {
    (((PRINTJOB *) printer->dataPtr)->pageNums) -= PAGESPERMINUTE;    
    if ((((PRINTJOB *) printer->dataPtr)->pageNums) <= 0) {
        printer = NULL;   //set pointer back to null (?)
    }
    printf("printers pageNum is: %d\n", ((PRINTJOB *) printer->dataPtr)->pageNums);
} // else nothing to do

还有其他可能性,具体取决于列表的结构和使用方式。

请注意,我从您的原始代码中复制的 printer = NULL; 行是有问题的。如果以后的代码在进行更多处理之前对printer 执行空检查,并且您想规避它,这可能是有意义的。但是请注意,未能首先free() 节点可能会构成内存泄漏。这样看起来很可疑,但有可能该节点真的不应该在那里被释放。

不过,还请注意,您的 deleteNode() 函数在对空列表进行操作时似乎可能会中断。在那种情况下,似乎它可以返回的唯一明智的东西是空指针。在这种情况下,list-&gt;head 实际上可能就是这样一个指针,但是

    NODE *toDelete;
    toDelete = list->head;
    list->head = toDelete->next;

将在评估toDelete-&gt;next 时尝试取消引用该空指针,从而获得未定义的行为。如果实际上您可以在列表为空时依赖list-&gt;head 为空,那么您可能需要像这样修改上面的内容:

    NODE *toDelete;
    toDelete = list->head;
    if (toDelete != NULL) {
        list->head = toDelete->next;
    } // else list->head is already NULL

同样,根据列表的结构和使用方式,还有其他可能性,但我认为以上可能是您想要的。

【讨论】:

    猜你喜欢
    • 2020-02-04
    • 2021-02-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多