在C中反转链接列表时出现运行时错误

时间:2013-10-26 00:20:51

标签: c pointers linked-list

我正在创建一个简单的整数链接列表,然后将其反转。在反转时,原始列表中的最后一个整数不会被打印。而是打印垃圾值。这是代码:

#include<stdio.h>
#include<stdlib.h>
struct list
{
    int node;
    struct list *next; 
};

void insert(struct list **, int);
void print(struct list *);

int main()
{
    struct list *mylist= NULL, *tmp = NULL;

    insert(&mylist, 10);

    tmp = mylist;
    insert(&mylist, 20);
    insert(&mylist, 30);
    insert(&mylist, 40);
    insert(&mylist, 50);
    insert(&mylist, 60);
    insert(&mylist, 70);
    mylist=tmp;
    reverse(&mylist);
    printf("hello  ");
    print(mylist);

    return 0;
}

void reverse(struct list **temp)
{
    struct list **pre, **aft, **head;
    *pre = NULL;
    *head = *temp;
    if(*head == NULL )
        {
        return;
        }
    else
    {
        while((*head)!= NULL)
        {

        *aft =(*head)->next;

        (*head)->next = *pre;
        *pre = *head;
        *head = (*aft);
         printf("%d\t",(*pre)->node);
        }

    *temp = *pre;         
    }           
    }

void print(struct list *head)
{
    if(head==NULL)
        return;
    else
    {
            while(head!=NULL)
            {
             printf("%d\t",head->node);
             head=head->next;       
        }
    }
}


void insert(struct list **head, int value)
{   
    struct list *new_node;
    new_node = (struct list *)malloc(sizeof(struct list));

//node Creation
    new_node->node=value;
    new_node->next=NULL;

//Adding Node to list
    if(*head==NULL)
    {
        *head=new_node;  

    }
    else
    {
        while((*head)->next!=NULL)
        {   
            *head=(*head)->next;

        }
        (*head)->next=new_node;

    }

}

输出: 10 20 30 40 50 60 6532425 hello 6532425 60 50 40 30 20 10

为什么?

2 个答案:

答案 0 :(得分:2)

问题出在这个声明中:

struct list **pre, **aft, **head;

因此,它们指向指向列表的指针,然后,您执行以下操作:

*pre = NULL;

问题是pre尚未初始化,因此此时它会保留垃圾。您基本上将内存中的随机地址设置为NULL。 您有两种选择:为它们分配空间(使用malloc和之后的空闲),或者将它们更改为:

struct list *pre, *aft, *head;

这样,他们可以安全地分配。您的功能将被修改如下:

void reverse(struct list **temp) {
    struct list *pre, *aft, *head;
    pre = NULL;
    head = *temp;
    if(head == NULL ) {
        return;
    } else {
        while(head!= NULL) {
            aft =head->next;
            head->next = pre;
            pre = head;
            head = aft;
            printf("%d\t",pre->node);
        }
        *temp = pre;
    }
}

这样做,我得到以下输出:

10      20      30      40      50      60      70      hello  70       60
50      40      30      20      10

编辑:

我还注意到您正在更改headinsert内的print值。我建议使用时态变量来迭代列表。这也让您摆脱了maintmp使用的技巧。

无论如何,可以看到修改后的完整代码here。如果您仍然遇到麻烦,请使用仍然失败的修改后的代码发布更新或Ideone链接。

答案 1 :(得分:2)

首先,通过这样做来解除引用并写入不确定的位置:

struct list **pre, **aft, **head;
*pre = NULL;    // <=== HERE
*head = *temp;  // <=== HERE

这些指针都没有被初始化为任何东西,因此是不确定的。取消引用它们进行读取,写入甚至评估指针值本身是未定义的行为

修复这很容易,因为这个函数不需要任何指针到指针变量,除了传入的头指针(它必须有by-address才能重置新的列表头一次)它是颠倒的)。

void reverse(struct list **head)
{
    struct list *back = NULL, *cur = *head, *fwd = NULL;
    while (cur && cur->next)
    {
        fwd = cur->next;
        cur->next = back;
        back = cur;
        cur = fwd;
    }

    if (cur)
        cur->next = back;

    *head = cur;
}

那就是说,证据表明你的指针指针需要更多的练习。还有其他错误,请参阅


insert()

中的内存泄漏

insert()函数中:

while((*head)->next!=NULL)
{
    *head=(*head)->next;

}
(*head)->next=new_node;

此代码盲目地覆盖传入的头指针by-address,并且在此过程中泄漏任何先前分配的节点,除了最后添加的节点。如果您要接收双指针并使用它来遍历列表以查找新插入的位置,请正确执行。在tmp中使用main()播放的指针游戏不一定是必要的,并且通过以下实现,它不是:

void insert(struct list **head, int value)
{
    // find the address of the last `next` pointer in
    // the list. note: it may be the head pointer itself
    while (*head)
        head = &(*head)->next; 

    *head = malloc(sizeof(**head));
    (*head)->node = value;
    (*head)->next = NULL;
}

简化print()

print()代码中的轻微不便也会出现。传入的指针不需要初始检查为NULL。只需使用while循环的break条件:

void print(struct list *head)
{
    while(head)
    {
        printf("%d ",head->node);
        head=head->next;
    }
    printf("\n");
}

全部放在一起

使用上述实现和以下main()

int main()
{
    struct list *mylist = NULL;

    insert(&mylist, 10);
    insert(&mylist, 20);
    insert(&mylist, 30);
    insert(&mylist, 40);
    insert(&mylist, 50);
    insert(&mylist, 60);
    insert(&mylist, 70);

    print(mylist);
    reverse(&mylist);
    print(mylist);

    return 0;
}

<强>输出

10 20 30 40 50 60 70 
70 60 50 40 30 20 10