问题描述
因此,我开始研究C语言中的数据结构,并希望编写一个单链表。
这只是其中的一小部分:
struct nodes {
int val;
struct nodes *next;
};
void insert(struct nodes *list,int val) {
struct nodes *tmp = (struct nodes*) malloc(sizeof(struct nodes));
tmp->val = val;
tmp->next = list;
list = tmp;
}
int main() {
struct nodes *test;
insert(test,5);
insert(test,10);
printf("test %d\n",test->next->val);
}
这里我得到完全错误的输出。当我尝试编写不需要传递结构指针的函数时,它的工作原理与预期的一样。
输出:
test 90053
P.S我仍然从C开始,所以不要太刻苦:D
解决方法
您正在更改局部变量,因此对调用方没有影响。您可能的意思是使用指向指针的指针,以便可以对其进行更改:
var url = `Mysite:3000/from/here/${othervars}?orgId=1&refresh=30s`
现在的功能如下:
int main() {
struct nodes *test = NULL; // Don't forget to initialize
insert(&test,5);
insert(&test,10);
printf("test %d\n",test->next->val);
}
由于void insert(struct nodes **list,int val) {
struct nodes *tmp = malloc(sizeof(struct nodes)); // No need to cast malloc() in C
tmp->val = val;
tmp->next = *list;
*list = tmp;
}
被取消引用(list
),因此实际上更改了原始值(指向),这意味着列表头发生了更改。
在您的原始代码中,您从未初始化过*list
,这只是一些随机的垃圾值,并且由于list
永远无法更改它,因此它仍然是垃圾数据。通过这种方式访问任何数据都是未定义的行为,因此您将得到垃圾数据或崩溃。
您可以这样:
struct nodes {
int val;
struct nodes* next;
};
nodes* insert(struct nodes* list,int val) {
struct nodes* tmp = (struct nodes*)malloc(sizeof(struct nodes));
tmp->val = val;
tmp->next = list;
return tmp;
}
在尝试编写类似第一个函数的结构时,我相信---是list()而不是insert()。
在每个可以更改列表起始地址的功能中,您必须返回地址,否则它将丢失。而且由于您仅在开始处插入,所以丢失了所有内容,因为开始地址始终会更改。
通常不要使用void
。至少是浪费,通常是一个错误。返回一些信息,例如完成状态。查看list()
的实现,该实现返回... size
int list(struct nodes* list)
{
struct nodes* p = list;
int N = 0;
while (p != NULL)
{
printf("#%d %d\n",N,p->val);
p = p->next; N += 1;
};
printf("\n");
return N;
}
和使用2个函数的main()版本
int main() {
struct nodes* test = NULL;
int n = 0;
for(n = 800; n>0; n-= 100) test = insert(test,n);
n = list(test);
printf("At the end list() returned %d\n",n);
}
这样,您可以从一开始就获得更多信息。
#0 100
#1 200
#2 300
#3 400
#4 500
#5 600
#6 700
#7 800
At the end list() returned 8
测试程序
#include <stdio.h>
#include <stdlib.h>
struct no
{
void* item;
struct no* next;
struct no* prev;
}; // no
typedef struct no Node;
typedef struct
{
char* name;
unsigned size;
unsigned limit;
Node* start;
Node* end;
} List;
struct nodes {
int val;
struct nodes* next;
};
struct nodes* insert(struct nodes*,int);
int list(struct nodes* L);
int main() {
struct nodes* test = NULL;
int n = 0;
for(n = 800; n>0; n-= 100) test = insert(test,n);
}
struct nodes* insert(struct nodes* list,int val) {
struct nodes* tmp = (struct nodes*)malloc(sizeof(struct nodes));
tmp->val = val;
tmp->next = list;
return tmp;
}
int list(struct nodes* list)
{
struct nodes* p = list;
int N = 0;
while (p != NULL)
{
printf("#%d %d\n",p->val);
p = p->next; N += 1;
};
printf("\n");
return N;
}
如评论中所指出,请注意,列表不是node
。节点集合的列表,并且节点具有数据有效负载。如果有效载荷是(void*)
,那么您将拥有一个真正的抽象数据结构,因为它可以加载任何内容,从单个char
到100-fields structure
。
考虑一下编写方式以及程序中有5个列表的情况:一团糟,它将变得非常快。并与下面的代码进行比较
链接列表结构
struct no
{
void* item;
struct no* next;
struct no* prev;
}; // no
typedef struct no Node;
typedef struct
{
char* name;
unsigned size;
unsigned limit;
Node* start;
Node* end;
} List;
请注意,随着您在List
中添加更多信息,事情变得更加容易:您始终拥有大小,限制,开始和结束的指针等等