C 反向打印双链接列表

C 反向打印双链接列表,c,C,我有一个可以从上到下打印的双链接列表,现在我正尝试从下到上打印它 #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 typede

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

#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
我也不知道为什么它不会反向打印完整的列表。反向打印时只打印一个项目

直到“最后一个节点数据打印”消息正确为止。是的,这有点混乱,我是C新手,我需要整理我的评论等等。抱歉


有人能帮忙吗?

在读取阶段,您设置了
last->next
,但从未将任何
prev
成员设置为除
NULL
之外的任何值

如果使用
%p
转换说明符修改
printList()
代码以打印
prev
next
成员,则可以看到这一点

例如:

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上):

正如您所看到的,没有反向链接,因此在打印一个元素(无论您指向哪个元素)后,反向打印停止

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

扫描代码中的修复很简单:

    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抱怨我的默认编译选项“可能未初始化使用”。它实际上并不是在未初始化的情况下使用的,但编译器(GCC6.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->next
,但从未将任何
prev
成员设置为
NULL
以外的任何值

如果使用
%p
转换说明符修改
printList()
代码以打印
prev
next
成员,则可以看到这一点

例如:

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上):

正如您所看到的,没有反向链接,因此在打印一个元素(无论您指向哪个元素)后,反向打印停止

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

扫描代码中的修复很简单:

    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抱怨我的默认编译选项“可能未初始化使用”。它实际上并不是在未初始化的情况下使用的,但编译器(GCC6.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.

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


顺便说一下,
temp
未使用。

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


顺便说一下,
temp
是未使用的。

您忘了链接到
prev

else last->next=ptr

应该是

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

你忘了链接到
prev

else last->next=ptr

应该是

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

请注意,点
和箭头
->
运算符绑定非常紧密,不应使用空格进行书写。(是的,它在语法上是有效的;可以将它们放在与结构/指针和成员名分开的一行上,并且编译它。这是一个正常或常规的演示问题——C和C++的编写方式)。您将
last->next
设置为空,但从未将任何
prev
成员设置为空。在向前打印列表时,应使用
%p
格式打印地址(下一个
上一个
成员);您将在
下一个
值中看到太多的空指针。请注意,点
和箭头
->
运算符绑定非常紧密,不应使用空格进行书写。(是的,它在语法上是有效的;可以将它们放在与结构/指针和成员名分开的一行上,并且编译它。这是一个正常或常规的演示问题——C和C++的编写方式)。您将
last->next
设置为空,但从未将任何
prev
成员设置为空。在向前打印列表时,应使用
%p
格式打印地址(下一个
上一个
成员);您将在
next
值中看到太多的空指针。非常感谢您的帮助和详细的解释。我选择这个作为答案,因为它有效,也因为你的解释。我急忙去做修复,没有看到你最后一次说的初始化