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列表),以及如何处理不成功的分配,但有了这些更改,您的代码至少应该编译并运行。