【问题标题】:printing a doubly linked list in reverse反向打印双向链表
【发布时间】:2016-09-18 04:18:32
【问题描述】:

我有一个可以从上到下打印的双向链表,现在我正在尝试从下到上打印它。

#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>

//defines the struct UserData
typedef struct
{
    int importance;
    char taskName[80];
}UserData, *UserDataPtr;

//Defines a node
typedef struct node {
    UserData Data;
    struct node *next;
    struct node *prev;
    } Node, *NodePtr;

NodePtr makeNode(UserData);

//Declare function printList
void printList(NodePtr);

void printListRev(NodePtr);

int main()
{
   UserData info;
   NodePtr top, ptr, last, temp;



   top = NULL;

    FILE *filein=fopen("Data.txt", "r");
    if (filein == NULL) {
        printf("Error opening file, exiting program.\n");
        exit(0);
    }

    while(fscanf(filein, "%d%s",&info.importance, info.taskName)==2)
        {
            ptr=makeNode(info);
            if (top == NULL) top = ptr;
            else last -> next = ptr;
            last = ptr;
        }//end while loop

    printList(top);


    printListRev(last);
   }//end Main


//printList is a function that prints each node as long as it isn't NULL. Once it reaches NULL it terminates, signifying the end of the list.
void printList(NodePtr ptr) {
    while (ptr != NULL) { //as long as there's a node
            printf("%d %s\n", ptr -> Data.importance, ptr -> Data.taskName);
            ptr = ptr -> next; //go on to the next node

        }
    if (ptr == NULL) {

        printf("Last node data printed moving forward.\n");
    }

    } //end printList


void printListRev(NodePtr ptr) {
    while(ptr != NULL){
        printf("%d %s\n", ptr -> Data.importance, ptr -> Data.taskName);
        ptr = ptr -> prev;


      }
    }//end printListRev

//Define function makeNode. Allocates storage for node, stores integer given to it, and returns a pointer to the new node. Also sets next field to NULL
NodePtr makeNode(UserData info) {
    NodePtr ptr = (NodePtr) malloc(sizeof (Node));
    ptr -> Data = info;
    ptr -> next = NULL;
    ptr -> prev = NULL;
    return ptr;
} //End makeNode

这是输出:

1 task1
2 task2A
3 task3A
2 task2B
4 task4A
4 task4B
3 task3B
Last node data printed moving forward.
3 task3B

而且我不知道为什么它不会反向打印完整列表。反向打印时只打印一项。

直到“打印最后一个节点数据”消息之前的所有内容都是正确的。是的,它有点乱,我是 C 新手,我需要清理我的 cmets 等。道歉。

谁能帮忙?

【问题讨论】:

  • 请注意,点. 和箭头-&gt; 操作符绑定得非常紧密,绝对不能在它们周围写上空格。 (是的,它在语法上是有效的;您可以将它们放在与结构/指针和成员名称不同的行上,它会编译。这是一个正常或传统表示的问题——C 和 C++ 的编写方式。)跨度>
  • 在读取阶段,您设置了last-&gt;next,但您从未将任何prev 成员设置为NULL 以外的任何值。在向前打印列表时,您应该使用%p 格式打印地址(nextprev 成员);您会在 next 值中看到太多空指针。

标签: c


【解决方案1】:

将节点插入列表时,您忘记将prev 字段设置为适当的值。修复很简单:将last 初始化为NULL,然后在ptr = makeNode(info); 行之后设置ptr-&gt;prev = last;

顺便说一句,temp 没有使用。

【讨论】:

  • 完全正确,您的解决方案有效。我给了@Jonathan 他解释的答案,但感谢您的回复!非常感谢您指出未使用的temp,但我之前尝试过之后忘记删除它(不成功,哈哈!)
  • 其实我没注意,编译器做了=))
【解决方案2】:

在读取阶段,您设置了last-&gt;next,但您从未将任何prev 成员设置为NULL 以外的任何成员。

如果您修改 printList() 代码以打印 prevnext 成员也可以看到这一点 - 使用 %p 转换说明符。

例如:

void printList(NodePtr ptr)
{
    while (ptr != NULL)
    {
        printf("%d %s (N = %p, P = %p)\n", ptr->Data.importance, ptr->Data.taskName,
               (void *)ptr->next, (void *)ptr->prev);
        ptr = ptr->next;
    }
    if (ptr == NULL)
    {
        printf("Last node data printed moving forward.\n");
    }
}

运行时,这会产生(对我来说,在我的 Mac 上):

1 task1 (N = 0x7ff6a94032e0, P = 0x0)
2 task2A (N = 0x7ff6a9403370, P = 0x0)
3 task3A (N = 0x7ff6a94033e0, P = 0x0)
2 task2B (N = 0x7ff6a9403450, P = 0x0)
4 task4A (N = 0x7ff6a94034c0, P = 0x0)
4 task4B (N = 0x7ff6a9403530, P = 0x0)
3 task3B (N = 0x0, P = 0x0)
Last node data printed moving forward.
3 task3B

如您所见,反向没有链接,因此反向打印在打印一个元素后停止 - 无论您指向哪个元素。

请注意,在编写 C 时,不应在点 . 或箭头 -&gt; 运算符周围使用空格。它们绑定得非常紧密,不应使用空格(尽管它在语法上是合法的)。如果您使用这种非正统的布局,您的代码的可读性会大大降低。

扫码中的修复很简单:

    while (fscanf(filein, "%d%s", &info.importance, info.taskName) == 2)
    {
        ptr = makeNode(info);
        if (top == NULL)
            top = ptr;
        else
            last->next = ptr;
        ptr->prev = last;
        last = ptr;
    }

我还在循环开始之前初始化了last = NULL;;当您使用它来设置前一个指针时,这一点至关重要。您之前可以省略它,尽管 GCC 抱怨我的默认编译选项“可能未初始化”。它实际上并没有在未初始化的情况下使用,但编译器 (GCC 6.2.0) 的担心是可以理解的。

进行此更改后,输出为:

1 task1 (N = 0x7fa4b1602a10, P = 0x0)
2 task2A (N = 0x7fa4b1602aa0, P = 0x7fa4b16029a0)
3 task3A (N = 0x7fa4b1602b10, P = 0x7fa4b1602a10)
2 task2B (N = 0x7fa4b1602b80, P = 0x7fa4b1602aa0)
4 task4A (N = 0x7fa4b1602bf0, P = 0x7fa4b1602b10)
4 task4B (N = 0x7fa4b1602c60, P = 0x7fa4b1602b80)
3 task3B (N = 0x0, P = 0x7fa4b1602bf0)
Last node data printed moving forward.
3 task3B
4 task4B
4 task4A
2 task2B
3 task3A
2 task2A
1 task1

你也可以打印节点的地址;这将使跟踪每个列表指针都指向正确的位置变得更容易:

void printList(NodePtr ptr)
{
    while (ptr != NULL)
    {
        printf("%d %s (C = %p, N = %p, P = %p)\n", ptr->Data.importance, ptr->Data.taskName,
               (void *)ptr, (void *)ptr->next, (void *)ptr->prev);
        ptr = ptr->next;
    }
    printf("Last node data printed moving forward.\n");
}

void printListRev(NodePtr ptr)
{
    while (ptr != NULL)
    {
        printf("%d %s (C = %p, N = %p, P = %p)\n", ptr->Data.importance, ptr->Data.taskName,
               (void *)ptr, (void *)ptr->next, (void *)ptr->prev);
        ptr = ptr->prev;
    }
    printf("Last node data printed moving backward.\n");
}

制作:

1 task1 (C = 0x7fd301c03270, N = 0x7fd301c032e0, P = 0x0)
2 task2A (C = 0x7fd301c032e0, N = 0x7fd301c03370, P = 0x7fd301c03270)
3 task3A (C = 0x7fd301c03370, N = 0x7fd301c033e0, P = 0x7fd301c032e0)
2 task2B (C = 0x7fd301c033e0, N = 0x7fd301c03450, P = 0x7fd301c03370)
4 task4A (C = 0x7fd301c03450, N = 0x7fd301c034c0, P = 0x7fd301c033e0)
4 task4B (C = 0x7fd301c034c0, N = 0x7fd301c03530, P = 0x7fd301c03450)
3 task3B (C = 0x7fd301c03530, N = 0x0, P = 0x7fd301c034c0)
Last node data printed moving forward.
3 task3B (C = 0x7fd301c03530, N = 0x0, P = 0x7fd301c034c0)
4 task4B (C = 0x7fd301c034c0, N = 0x7fd301c03530, P = 0x7fd301c03450)
4 task4A (C = 0x7fd301c03450, N = 0x7fd301c034c0, P = 0x7fd301c033e0)
2 task2B (C = 0x7fd301c033e0, N = 0x7fd301c03450, P = 0x7fd301c03370)
3 task3A (C = 0x7fd301c03370, N = 0x7fd301c033e0, P = 0x7fd301c032e0)
2 task2A (C = 0x7fd301c032e0, N = 0x7fd301c03370, P = 0x7fd301c03270)
1 task1 (C = 0x7fd301c03270, N = 0x7fd301c032e0, P = 0x0)
Last node data printed moving backward.

【讨论】:

  • 非常感谢您的帮助和详尽的解释。我选择这个作为答案是因为它有效并且因为你的解释。我急于进行修复,没有看到你所说的关于将 last 初始化为 NULL 的内容,最后我也得到了一些时髦的输出,但是在将 last 初始化为 NULL 时,它完全按照你的描述工作。我希望我能获得足够的经验,像你一样帮助别人!
【解决方案3】:

你忘记了链接到prev

else last -&gt; next = ptr;

应该是

else {
    ptr->prev = last;
    last -> next = ptr;
}

【讨论】:

  • last 不需要初始化。 (虽然是个好习惯)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-11-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-01-15
  • 2012-04-08
相关资源
最近更新 更多