C链表指针问题(无限循环)



Edit:添加了新代码,当前的问题是,当我插入一个节点时,它可以正常工作,但如果我插入多个节点,insert_node方法永远不会完成,第一条语句会打印出来,说"insert called",然后它永远不会完成"insert complete"。

我唯一能想到的是while循环条件,但我不明白为什么它是无限的。

此外,当我插入1个节点时,它打印得很好,但从未停止打印,又是一个无限循环。

关于上述错误的原因有什么想法吗?

 /* 
 * File:   main.c
 * Author: che16
 *
 * Created on 20 November 2013, 08:59
 */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "structure.h"
/*
 * 
 */
node* head = NULL;
int set_head = 0;
int main(int argc, char** argv) {
    int no;
    printf("enter amount of books n");
    scanf("%d", &no);
    create_books(no);
    print_list(head);

    return (EXIT_SUCCESS);
}
node* create_books(int no_of_books) {
    char title[50];
    char author[30];
    unsigned int number;
    int i;
    for (i = 0; i < no_of_books; i++) {
        node* new_node;
        new_node = (node *) malloc(sizeof (node));
        printf("enter book title n");
        scanf("%s", title);
        printf("enter author name n");
        scanf("%s", author);
        printf("enter ISDN number n");
        scanf("%10u", &number);
        strncpy(new_node->btitle, title, 40);
        strncpy(new_node->name, author, 40);
        new_node->isbn = number;
        new_node->n = NULL;
        if (!set_head) {
            head = new_node;
            insert_node(head, new_node);
            set_head = 1;
            continue;
        }
        insert_node(head, new_node);
    }
}
void insert_node(node* head, node* insert) {
    printf("insert called n");
    insert->n = NULL;
    if (head == NULL) {
        head = insert;
    } else {
        node* curr = head;
        while (curr->n != NULL) {
            curr = curr->n;
        }
        curr->n = insert;
    }
    printf("insert complete n");
}
void delete_node(node* head, node * node) {
}
void print_list(node * head) {
    while (head) {
        printf("%s: "%s" (%u)n", head->btitle, head->name, head->isbn);
        head = head->n;
    }
}

您的代码有几个问题。

首先,您分配了太多内存。临时局部变量只是指向现有内存的指针。唯一需要分配内存的地方是create_book,在这里可以创建数据。您必须稍后通过删除节点来free该内存。(我想你可能会对指针所扮演的不同角色感到困惑:有时它们只是识别新分配的内存,更多时候是用来访问和遍历现有内存。)

接下来,head本身并不是一个节点,它只是指向第一个节点的指针。如果没有节点,则此指针为NULL。这在程序开始时是正确的,这意味着你必须初始化它:

node* head = NULL;

但如果所有的书都被从名单中删除了,那也是真的。显然,如果添加第一个节点或删除第一个节点,head就会发生变化。您的insert_node应该处理这些更改。一种方法是将头作为指针传递给节点指针。

(在C中,作为参数传递的所有内容都是本地副本。更改is将使调用函数中的原始值保持不变。但如果您传递指针,则指向的内容在调用和被调用函数中都是相同的。您可以通过指针更改它。)

此外,是否需要更改head应该是insert_node的问题,而不是main中的调用(客户端)代码的问题。如果你跳过所有错误的malloc,插入会容易得多:

void insert_node(node **head, node* insert)
{
    insert->n = NULL;
    if (*head == NULL) {
        *head = insert;
    } else {
        node* curr = *head;
        while (curr->n) curr = curr->n;
        curr->n = insert;
    }
}

你可以从main无条件地这样调用:

insert_node(&head, create_book(title, author, number));

请注意,所有这些都会使head_set变得多余:如果设置了head,它就有一个合法的指针值,否则它就是NULL

由于结构没有名称,因此会出现抱怨不兼容指针的编译器错误。在C中,结构类型由单词struct和它的名称定义。有些人认为struct关键字是不必要的,typedef是单个单词类型的结构。你可以在一句话中做到这一点。您可以申报:

typedef struct node {
    char btitle[40];
    char name[40];
    unsigned int isbn;
    struct node* n;
} node;

或者你可以把类型和结构分开:

typedef struct node node;
struct node {
    char btitle[40];
    char name[40];
    unsigned int isbn;
    struct node* n;
};

typedef可能进入主源文件中的头和结构。)

您会注意到我已将char *btitle更改为char btitle[40]。如果您只存储一个指向标题的指针,那么实际上您将一个指向本地缓冲区title的指针存储在main中。该缓冲区用于循环中的输入,在打印书籍时,该缓冲区包含第三本书的值。这意味着列表中的所有书籍都将具有相同的名称和作者。

解决这个问题的一种方法是将指向的缓冲区的内容复制到结构中,当然,结构必须为其缓冲区提供内存,如上所示。您的create_book变成:

node* create_book(char* t, char* auth, unsigned int num)
{
    node* new_node;
    new_node = malloc(sizeof (node));
    strncpy(new_node->btitle, t, 40);
    strncpy(new_node->name, auth, 40);
    new_node->isbn = num;
    new_node->n = NULL;
    return new_node;
}

例程CCD_ 23将最多40个字符从第二缓冲器复制到第一缓冲器。您应该为原型包含<string.h>。还要注意,我将指向下一个节点的指针n显式初始化为NULL,就像我在main中对head所做的那样。下一个节点指针是NULL或始终指向有效节点的指针。

现在插入工作了,打印列表很容易:

void print_list(node* head)
{
    while (head) {
        printf("%s: "%s" (%u)n", head->btitle, head->name, head->isbn);
        head = head->n;
    }
}

查看代码如何仅使用包含在节点本身中的数据,以及如何使用head == NULL或简称head作为到达列表末尾的方便标准。(print_node函数不需要将head作为指向节点指针的指针传递,因为它从不更改列表,只检查其数据。)

仍然有一些问题需要解决,比如在使用后删除节点(或while列表),以及如何处理不成功的分配,但有了这些更改,您的代码至少应该编译并运行。

相关内容

  • 没有找到相关文章

最新更新