c - 为什么这段用于反向打印单向链表的代码段没有按预期工作?

标签 c pointers linked-list reverse singly-linked-list

int printRev(void *l)
{
    list_sll *list= (list_sll *)l;
    int i= list->noOfNodes-1;
    node_sll *subject= malloc(sizeof(node_sll));
    subject->next= list->start;
    node_sll *front= NULL;  /*node directly in front of subject*/
    do {
        while(subject->next!=front)
            subject= subject->next;
        printf("%d. %d\n", i, subject->data);
        front= subject;
        subject->next= list->start;
        --i;
    }
    while(front!=list->start);
    subject= NULL;
    free(subject);
    return 0;
}

我将用于存储链接列表(已创建)所需详细信息的结构地址(定义如下)传递给 printRev() 函数,该函数接受它作为指向 void 的指针。 这是最小的可行代码:

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

typedef struct node_sll
{
int data;
struct node_sll *next;
} node_sll;

typedef struct list_sll
{
struct node_sll *start;
int noOfNodes;
} list_sll;

int printlist(void *);
int printRev(void *);
int insert(void *, int);

int main(void)
{
    list_sll list1;
    list1.noOfNodes= 1;
    printf("Creating the first node\nEnter the data\n");
    int d;
    scanf("%d", &d);
    node_sll node1;
    node1.data= d;
    node1.next= NULL;
    list1.start= &node1;
    int choice;
    do {
        printf( "\nEnter:\n1. INSERT: to insert the node\n"
        "2. PRINT: print the list\n"
        "3. PRINT@rev: print the list in reverse order\n"
        "0. QUIT: quit this menu\n");
        scanf("%d", &choice);
        switch(choice) {
            case 1:
                printf("Enter the node data\n");
                insert(&list1, list1.noOfNodes);
                break;
            case 2:
                printlist(&list1);
                break;
            case 3:
                printRev(&list1);
                break;
        } 
    }
    while(choice);
    return 0;
}

int printlist(void *l)
{
    struct list_sll *list= (list_sll *)l;
    struct node_sll *p= list->start;
    int count= 0;
    printf("no of nodes: %d\n", list->noOfNodes);
    while(p!=NULL && count < list->noOfNodes) {
        printf("%d. %d\n", count, p->data);
        p=p->next;
        ++count;
    }
    return 0;
}

int insert(void *l, int pos)
{
    struct list_sll *list= (list_sll *)l;
    struct node_sll *current= malloc(sizeof(node_sll));
    int n;
    scanf("%d", &(current->data));
    current->next= list->start;
    struct node_sll *prev_node= NULL;
    while(pos--) {
    prev_node= current->next;
    current->next= current->next->next;
    }
    if(prev_node==NULL)
        list->start= current;
    else
        prev_node->next= current;
    ++(list->noOfNodes);
    printf("No of nodes %d\n", list->noOfNodes);
    return 0;
}

int printRev(void *l)
{
    list_sll *list= (list_sll *)l;
    int i= list->noOfNodes-1;
    node_sll *subject= malloc(sizeof(node_sll));
    subject->next= list->start;
    node_sll *front= NULL;  /*node directly in front of subject*/
    do {
        while(subject->next!=front)
            subject= subject->next;
        printf("%d. %d\n", i, subject->data);
        front= subject;
        subject->next= list->start;
        --i;
    }
    while(front!=list->start);
    subject= NULL;
    free(subject);
    return 0;
}

当我调用 printRev( ) 函数时,会打印反向列表,但由于某种我无法弄清楚的原因,列表元素在打印完成后发生了变化。现在所有节点存储相同的数据,该数据等于第一个节点的数据值。当我只更改一些指针时,为什么数据会发生更改? 在尝试调试时,我创建了一个列表(节点 - 10、20、30、40)并在 printRev( ) 中添加了一些代码行:

int printRev(void *l)
{
    list_sll *list= (list_sll *)l;
    int i= list->noOfNodes-1;
    node_sll *subject= malloc(sizeof(node_sll));
    subject->next= list->start;
    node_sll *front= NULL;  /*node directly in front of subject*/
    do {
        while(subject->next!=front)
            subject= subject->next;
        printf("%d. %d\n", i, subject->data);

        //printing current list status
        printf("%d", list->start->data);
        printf("%d", list->start->next->data);
        printf("%d", list->start->next->next->data);
        printf("%d", list->start->next->next->next->data);

        front= subject;
        subject->next= list->start;
        --i;
    }
    while(front!=list->start);
    subject= NULL;
    free(subject);
    return 0;
}

这是我调用此函数时得到的输出:

3.40
10
20
30
40

2.30
10
20
30
40

1.20
10
20
30
10

0.10
10
20
10
20

我无法找出问题所在。请帮忙。

最佳答案

对于初学者来说,该函数已经具有未定义的行为,因为它具有返回类型 int 但不返回任何内容。

不需要动态分配节点subject。可以将其声明为结构体类型的对象。

如果列表为空,这个 do-while 循环也可能导致未定义的行为

do {
    while(subject->next!=front)
        subject= subject->next;
    printf("%d. %d\n", i, subject->data);
    //...
}
while(front!=list->start);

因为将尝试访问空指针的值。

此外,在这个 do-while 循环中,指针subject 也发生了变化

do {
    while(subject->next!=front)
        subject= subject->next;
    // ...
    subject->next= list->start;
    // ...
}

因此原始列表也发生了变化。

这些陈述

subject= NULL;
free(subject);

由于指针subject指向的原始动态分配对象没有被释放,导致内存泄漏。

如果使用您的方法,那么该函数可以如下所示(无需测试)。

void printRev( void *l )
{
    list_sll *list = ( list_sll * )l;

    int i = list->noOfNodes;

    node_sll subject = { 0, list->start };

    node_sll *front = NULL;  /*node directly in front of subject*/

    while ( i != 0 )
    {
        node_sll *current = &subject;

        while ( current->next != front ) current = current->next;

        --i;

        printf( "%d. %d\n", i, current->data );

        front = current;
    }
}

关于c - 为什么这段用于反向打印单向链表的代码段没有按预期工作?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42890110/

相关文章:

java - 将链接列表转换为数组列表

java - 删除链接列表中第一次出现的项目

c - 在 C 语言中,每次使用 scanf 清除缓冲区时,我都应该使用 FLUSH 吗?

c - 数组和指针字符串声明之间的差异

python - 需要帮助将 C 函数移植到 Python

pointers - 如何在 Go 中将动态创建的结构作为非指针对象传递

c++ - 存储双指针地址并检索其值

Java Hashmap 尾部遍历

连接错误: simple socket programming in C in Ubuntu

c - 当我使用malloc时,如何在C中获取* char的大小?