C 如何将空指针(结构返回类型)更改为声明的结构?

C 如何将空指针(结构返回类型)更改为声明的结构?,c,pointers,struct,C,Pointers,Struct,我是C编程新手。我正在尝试自己实现链表。我遇到了指针的问题 我有功能 void Insert(Node* head, int x) 在链表的开头插入节点。问题是,当我插入第一个节点且node*head为NULL时,函数insert无法将NULL指针的指针地址更改为新创建的节点。似乎节点*头是通过值传递的,而不是通过引用传递的。 代码如下所示。为了调试地址在整个执行过程中的变化,我使用了printf函数 #include <stdio.h> #include <string.h

我是C编程新手。我正在尝试自己实现链表。我遇到了指针的问题

我有功能

void Insert(Node* head, int x)

在链表的开头插入节点。问题是,当我插入第一个节点且node*head为NULL时,函数insert无法将NULL指针的指针地址更改为新创建的节点。似乎节点*头是通过值传递的,而不是通过引用传递的。 代码如下所示。为了调试地址在整个执行过程中的变化,我使用了printf函数

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

typedef struct Node {
    int data;
    struct Node *next;
} Node;

int main() {
    Node *head = (Node*) malloc(sizeof(Node));
    head = NULL;

    printf("head in main(): %d\n", head); // For example: 100

    Insert(head, 25);
    return 0;
}

void Insert(Node *head, int x) {
    Node *temp = (Node*) malloc(sizeof(Node));
    temp->data = x;
    temp->next = head;

    printf("temp->next address: %d\n", temp->next); // also 100

    head = temp;

    printf("%d\n", head); // not 100, something else i.e  200
}
#包括
#包括
#包括
类型定义结构节点{
int数据;
结构节点*下一步;
}节点;
int main(){
Node*head=(Node*)malloc(sizeof(Node));
head=NULL;
printf(“head in main():%d\n”,head);//例如:100
插入(头,25);
返回0;
}
空心插入(节点*头部,整数x){
Node*temp=(Node*)malloc(sizeof(Node));
温度->数据=x;
温度->下一步=头部;
printf(“临时->下一个地址:%d\n”,临时->下一个);//也是100
压头=温度;
printf(“%d\n”,head);//不是100,而是200
}

将指针传递给指向头部的指针。这样,您可以将head设置为null

void插入(节点**头部,int x){
...
如果(*head==NULL){
*压头=温度;
}
否则{
...
*头部->下一步=温度;
}
}
用法:

节点*head=NULL;
插入(&头,10);

似乎节点*头是通过值传递的,而不是通过引用传递的

这是完全正确的——在C中,每个参数总是按值传递。指针是一个值,该值由值传递,调用

Insert(head, 25);
无法更改名为
head
的变量的值。它读取变量的值(该值为空指针),将该值提供给函数,并且无论函数执行什么操作,都不会再次接触变量

(请注意,在您的程序中,有两个变量都命名为
head
——一个在
main()
中,另一个在
Insert()
中。
Insert()
中的变量在函数返回时会自动消失;没有任何东西会自动尝试将其值复制到
main()
中类似命名的变量。)

如果您想(概念上)通过引用传递
head
,您需要实际传递一个指向它的指针——在本例中,就是指向指针的指针!您需要将函数声明为

void Insert(Node **head, int x) { ... }
并称之为

Insert(&head, 25);
然后,实际参数是一个指向变量
head
的指针,如果您在适当的情况下遵循该参数,则函数有机会更新该变量:

// ...
temp->next = *head;
// ...
*head = temp;
// ...

这里有很多问题。
1.您的printf语句需要更正。
2.要插入函数,可以传递双指针。
3.在main函数中,不需要执行
Node*head=(Node*)malloc(sizeof(Node))

我已经修改了您的代码,如下所示。你可以试着运行它,并将以上几点联系起来

typedef struct Node {
    int data;
    struct Node *next;
} Node;

void Insert(Node **head, int x);

void Insert(Node **head, int x) {
    Node *temp = (Node*) malloc(sizeof(Node));
    temp->data = x;
    temp->next = *head;

    printf("temp->next address: %d\n", temp->data); // also 100

    *head = temp;

    printf("%d\n", (*head)->data); // not 100, something else i.e  200
}

int main() {
    Node *head = NULL;
    head = NULL;

    Insert(&head, 25);
    printf("head in main(): %d\n", head->data); // For example: 100
    return 0;
}

有三个答案表明相同,我想提供一个替代方案: 您可以让它返回新的
头,而不是将
节点**
传递给
Insert()
,因此:

Node *Insert( Node *head, int x )
{
     ... your code ...
     return head;
}
如果你打过去

head = Insert( head, 24 );

与其他解决方案相比,这既不好也不坏,因此您可以做任何您喜欢的事情

传入指向
头的指针
,并相应地更改其余代码。“看起来节点*头是通过值传递的,而不是通过引用传递的。”确实如此。C中的所有内容都通过value
head=(Node*)malloc(sizeof(Node))传递;head=NULL哇。只需分配内存并立即将其丢弃即可。谈论内存泄漏。通过为链表创建一个结构并传递指向该结构的指针,可以绕过混淆和指针指向的内容:
struct LinkedList{Node*head;}
通过从函数返回新的
,您还可以绕过指向指针内容的指针。所以函数声明应该是
Node*Insert(Node*head,intx)
谢谢,它可以工作。我还有一个问题。上面评论中的一些人告诉我,通过声明动态内存并将其丢弃,我正在创建内存泄漏。问题是:我应该在堆或堆栈中创建头节点吗?@Genjik:JL2210的评论是正确的——如果您想从一个空列表开始,该列表只包含空指针,不包含
struct node
的实例。因此,开始分配一个
struct节点
之后再忘记它是没有意义的。
Insert
方法中的分配是您想要的。“不好也不坏”在什么意义上?这不完全一样