我正在编写一个程序,可以将元素插入到列表的末尾,然后显示其中一个。它插入正确,但我可以显示指定的一个。
typedef struct Node
{
int data;
struct Node *next;
struct Node *prev;
} node;
void insert(node *head, int data)
{
node *newNode = (node*) malloc(sizeof(node));
newNode->data = data;
newNode->next = NULL;
if(head == NULL)
{
head = newNode;
}
else
{
while(head != NULL)
head = head->next;
head->next = newNode;
(head->next)->prev = head;
}
}
void print(node *head, int element)
{
node *temp = head;
int count = 0, i = 1;
while(i < element)
{
temp = temp->next;
i++;
}
printf("%d", temp->data);
}
int main()
{
node *start = (node*) malloc(sizeof(node));
start = NULL;
int data1 = 4, data2 = 5;
insert(start,data1);
insert(start,data2);
print(start, 1);
}
为什么不起作用?另外,你能否告诉我我是否正确地做到了这一点?
答案 0 :(得分:1)
这是因为您按值传递了start
指针。这意味着一旦函数返回,insert
函数内的任何更改都将丢失。
您可以通过引用传递指针:
void insert(node **head, int data)
{
/* ... */
if (*head == NULL)
*head = newNode;
else
{
/* ... */
}
}
int main(void)
{
node *start = NULL;
insert(&start, 1);
/* ... */
}
或者从函数返回指针:
node *insert(node *head, int data)
{
/* ... */
return head;
}
int main(void)
{
node *start = NULL;
start = insert(start, 1);
insert(start, 2); /* Do not get the returned pointer, as the returned pointer no longer points to the start of the list */
/* ... */
}
这两种解决方案的问题在于,如果head
不是NULL
,则更改为insert
,指向最后一个节点之前的节点。在NULL
内的循环中,您应该使用临时指针。
作为安全预防措施,您应该检查print
功能中的循环中是否没有{{1}}节点。想想如果传递的数字大于列表中的节点数,会发生什么。
答案 1 :(得分:0)
请参阅我的修订评论内联main()
的代码段:
node *start = (node*) malloc(sizeof(node));//You allocate memory here. Good.
start = NULL;//Memory leak.
//Instead of the above two lines use this
node* start=NULL;
int data1 = 4, data2 = 5;
start=insert(start,data1);//If you want to do it statically, why not write insert(start,4)?
insert(start,data2);
....
我建议在print()
函数中添加NULL检查。
void print(node *head, int element)
{
//Null check for the start pointer.
//If you would have had this here, you'd have never faced such problem.
if(head == NULL)
{
//Handle null
}
node *temp = head;
int count = 0, i = 1;
....
}
加起来insert()
我会建议:
node* insert(node *head, int data)
{
node *newNode = (node*) malloc(sizeof(node));
newNode->data = data;
newNode->next = NULL;
if(head == NULL)
{
head = newNode;
return head;
}
else
{
while(head != NULL)
head = head->next;
head->next = newNode;
(head->next)->prev = head;
return NULL;
}
}
希望它有所帮助。
答案 2 :(得分:0)
有一个技巧可以让事情变得更容易,也可以提高你的代码效率!
技巧是使用循环列表,并使“head”节点成为sentinel值。空列表由指向自身的prev
和next
的单个节点表示。你永远不需要NULL,这种风格大大减少了你需要的特殊外壳。它还允许O(1)访问列表的头部和尾部。从不使用头部的data
字段。它在Knuth的“计算机编程艺术”中有所描述。
在这种风格中,你会得到这样的结论:[未经测试]
#include <stdio.h>
#include <stdlib.h>
typedef struct Node {
int data;
struct Node *next, *prev;
} node;
void insert_list(node *head, int data) {
node d = {data, head, head->prev};
node *new_node = malloc(sizeof(node));
/* TODO: handle malloc failure */
*new_node = d;
head->prev->next = new_node;
head->prev = new_node;
}
node *get_list(node *head, int n) {
node *node = head;
int i;
for (i = 0; i <= n; i++) {
node = node->next;
if (node == head) {
/* TODO: handle out-of-bounds index */
}
}
return node;
}
void print_list(node *head, int i) {
printf("%d\n", get_list(head, i)->data);
}
node *new_list(void) {
node *head = malloc(sizeof(node));
/* TODO: handle malloc failure */
head->next = head->prev = head;
return head;
}
int main(int argc, char**argv) {
node *list = new_list();
insert_list(list, 10);
insert_list(list, 20);
print_list(list, 0);
print_list(list, 1);
return 0;
}