我想制作一个链接列表,该链接列表是从我的主要其他地方调用的。该链表由节点组成。
例如,这不是我的代码只是它的简化版本。
#include <stdio.h>
#include <stdlib.h>
struct nodeTest
{
int data;
struct nodeTest* next;
};
然后我有另一个文件试图使用该结构:
#include <stdio.h>
#include <stdlib.h>
#include "nodeTest.h"
int main(void) {
struct nodeTest* first = malloc(sizeof(struct nodeTest));
first->data = 0;
return 0;
}
void addLL(int data){
if (first.data = 0)
{
printf("No head\n");
}
}
我想首先成为链表中的第一个元素,那么如何定义首先使用的addElement呢?现在,当我第一次打电话时,我收到一个无法识别的错误。
这是我在主
之后的链表文件中得到错误的地方void addLL(int data){
if (head.data = 0)
我在if行遇到错误,头部无法识别。
答案 0 :(得分:3)
右。您收到该错误是因为变量head
仅在main
内可见。有两种方法:
head
声明为全局变量;或head
传递给任何需要它作为指针的函数让我们看看这些选项是如何运作的:
#include <stdio.h>
#include <stdlib.h>
#include "nodeTest.h"
/* Declare a global variable. The initialization to NULL is redundant
* since global variables are automatically initialized to zero. But
* let's be thorough.
*/
struct nodeTest* head = NULL;
int main(void) {
head = malloc(sizeof(struct nodeTest));
/* check if head is NULL here. Just in case. */
head->data = 0;
addLL(1);
return 0;
}
/* other functions here */
void addLL(int data) {
/* since we allocate head in main it should never be NULL and
* if it is, something is wrong. So assert.
*/
assert(head != NULL);
/* Notice: in your original code you had: if (first.data = 0)
* which is wrong. First of all, there's no variable named first
* declared anywhere. If you meant head, that should have been
* head->first since head is a pointer. And lastly, first.data = 0
* would set first.data to 0, instead of comparing it for equivalency,
* and would then cause the if to never execute because the compiler
* would first set first.data to zero, then check first.data, and never
* enter the loop since it was zero.
*/
if (head->data == 0)
{
printf("No head");
return;
}
/* other code here */
}
此版本很简单,只需要很少的更改。一个好处是需要修改头部的功能可以轻松实现。
在非平凡的程序中,它确实需要很多全局变量,这被认为是糟糕的编程习惯,如果可能的话应该避免使用。
head
作为指针传递#include <stdio.h>
#include <stdlib.h>
#include "nodeTest.h"
int main(void) {
struct nodeTest* head = malloc(sizeof(struct nodeTest));
/* check if head is NULL here. Just in case. */
head->data = 0;
/* we call addLL, passing the head that we just allocated
* to it.
*/
addLL(1, head);
return 0;
}
void addLL(int data, struct nodeTest *head) {
if (head == NULL) || (head->data == 0))
{
printf("No head");
return;
}
/* other code here */
}
此方法要求我们将head
传递给每个可能需要它的函数。这使得函数接口稍微复杂化,但允许我们更灵活,因为我们不需要为我们程序中的许多列表提供许多全局变量。
但还有另一个问题。如果这些函数中的任何一个需要修改head
指针(例如,假设你要删除列表中的第一个元素)那么你就有问题了。指针(与指向的东西不同)是函数的本地指针,因此对函数所做的任何更改都将在函数外部不可见。
有两种方法可以解决这个问题:
head
作为参数并且可能需要更改它的每个函数都必须返回指向新头的指针。这有效,但实施起来很麻烦,而且很容易出错。head
作为参数并且可能需要更改它的每个函数都会接受一个双指针:一个指向头部指针的指针。这种方法运行良好,但使事情复杂化,可能会让一些新手程序员措手不及。它也有点容易出错,但没有上一个选项那么多。我希望这能回答你的问题,解释为什么你不能做你做过的事情以及现有的解决方法。
答案 1 :(得分:2)
问题0:理解链接列表和C
有很多材料。请查看这些slides from a lecture on data structures。
问题1:'未申报'
在使用变量之前,您需要先引入变量。问题是head
不在函数范围内(根据C规则)。因此,您需要将指针作为参数传递给它:
void addLL(struct nodeTest *head, int data){
// now you can access head->data, head->next
// ..
}
如果您使用0
表示没有可用数据,则无法存储任何零。
另一个你可以保持列表元素的数量,并检查计数
为零以确定列表是否为空。
问题2:'first-&gt; data'notclared
首先声明(与head
相同),或使用head->data
。
问题3:列表设计和API
通常认为使用全局状态是不好的做法,所以不要使用全局列表。
我建议你为列表定义另一个结构,并在list_add()
或list_remove()
等其他函数周围传递一个点,这样你也可以保存一个指向最后一个元素的指针来使appen成为O (1)操作,例如:
struct list {
struct node *first;
struct node *last;
unsigned long length;
};
那么,您可以实现一个函数来检查列表是否为空:
inline bool list_is_empty(struct list* l) {
assert(l != NULL);
return l->length;
}
并在main
中使用多个列表:
struct list *list1 = list_create(); // sets length to 0
struct list *list2 = list_create(); // return a new list
//...
list_add(&list1, data); // you pass a pointer to the list to which you want to add
//...
struct node *e = list_search(&list1, data);
if (e == NULL)
printf("not found\n");
//...
list_remove(&list1, data);
//
list_destroy(&list1);
可以像这样实现向列表中添加元素:
int list_add(struct list* l, int data) {
if (l == NULL)
return LIST_FAILURE; // or exit with an error message
l->last->next = list_elem_create(data); // dynamically creates a new node
l->last = l->last->next;
l->length++;
return LIST_SuCCESS; // symbolc constant defined elsewhere
}
答案 2 :(得分:1)
在调用main函数之前,您无法分配内存。您可以在main之外声明一个全局变量,并使用其地址作为第一个。 main中的alloc应该工作,这是最好的方法。但你必须对类似于下面的结构进行类型转换才能使用它,否则你的编译将失败
typedef struct First {
<element 1>
struct first *next
} First;
然后你可以这样做
First *first = NULL
first = (First *) malloc(sizeof(First));