您所拥有的会调用未定义的行为,因为您实际上并没有节点,您有一个指向实际上并不指向节点的节点的 指针。使用malloc 和朋友创建一个实际节点对象可以驻留以及节点指针可以指向的内存区域。
在您的代码中,struct node* head 是一个指向无处的指针,并且像您所做的那样取消引用它是未定义的行为(这通常会导致段错误)。您必须先将 head 指向有效的 struct node,然后才能安全地取消引用它。一种方法是这样的:
int main() {
struct node* head;
struct node myNode;
head = &myNode; // assigning the address of myNode to head, now head points somewhere
head->data = 2; // this is legal
printf("%d \n", head->data); // will print 2
}
但是在上面的例子中,myNode 是一个局部变量,一旦函数存在就会超出范围(在这种情况下是main)。正如您在问题中所说,对于链接列表,您通常希望 malloc 数据,以便可以在当前范围之外使用它。
int main() {
struct node* head = malloc(sizeof struct node);
if (head != NULL)
{
// we received a valid memory block, so we can safely dereference
// you should ALWAYS initialize/assign memory when you allocate it.
// malloc does not do this, but calloc does (initializes it to 0) if you want to use that
// you can use malloc and memset together.. in this case there's just
// two fields, so we can initialize via assignment.
head->data = 2;
head->next = NULL;
printf("%d \n", head->data);
// clean up memory when we're done using it
free(head);
}
else
{
// we were unable to obtain memory
fprintf(stderr, "Unable to allocate memory!\n");
}
return 0;
}
这是一个非常简单的例子。通常对于链表,您将拥有插入函数(通常发生mallocing 的地方和删除函数(通常发生freeing 的地方。你至少会有一个@ 987654332@ 指针始终指向列表中的第一项,对于双链表,您还需要一个 tail 指针。还可以有打印函数、deleteEntireList 函数等。但有一个方法或者,您必须为实际对象分配空间。malloc 是一种这样做的方法,因此内存的有效性在程序的整个运行时都保持不变。
编辑:
不正确。这绝对适用于int 和int*,它适用于任何对象和指向它的指针。如果您有以下情况:
int main() {
int* head;
*head = 2; // head uninitialized and unassigned, this is UB
printf("%d\n", *head); // UB again
return 0;
}
这是您在 OP 中的所有未定义行为。指针必须指向有效的东西,然后才能取消引用它。在上面的代码中,head 未初始化,它没有确定性地指向任何内容,并且一旦您执行*head(无论是读取还是写入),您就会调用未定义的行为。就像您的 struct node 一样,您必须执行以下操作才能正确:
int main() {
int myInt; // creates space for an actual int in automatic storage (most likely the stack)
int* head = &myInt; // now head points to a valid memory location, namely myInt
*head = 2; // now myInt == 2
printf("%d\n", *head); // prints 2
return 0;
}
或者你可以这样做
int main() {
int* head = malloc(sizeof int); // silly to malloc a single int, but this is for illustration purposes
if (head != NULL)
{
// space for an int was returned to us from the heap
*head = 2; // now the unnamed int that head points to is 2
printf("%d\n", *head); // prints out 2
// don't forget to clean up
free(head);
}
else
{
// handle error, print error message, etc
}
return 0;
}
这些规则适用于您正在处理的任何原始类型或数据结构。指针必须指向某些东西,否则取消引用它们是未定义的行为,并且您希望在发生这种情况时得到一个段错误,以便您可以在 TA 评分之前或在客户演示之前追踪错误。墨菲定律规定 UB 总是会在呈现代码时崩溃。