为什么我无法初始化 linkedlist?

Why am i not able to initialize the linkedlist?

提问人:Harshit Singh 提问时间:8/14/2023 最后编辑:Vlad from MoscowHarshit Singh 更新时间:8/15/2023 访问量:85

问:

我试图制作一个链接列表,但头部指针一直指向 null,因此在获取链接列表的大小和元素后没有输出。此外,当我将头部作为 Main 函数内部的指针时,当我尝试调用推送和显示函数时,它会给我分段错误。

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

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


void push(node *head,int value){
    node * newnode= (node*)malloc(sizeof(node));
    newnode->data = value;
    newnode->next = NULL;
    printf("%d",value);
    if(head==NULL){
        head = newnode;
        return;

    }
    node* iter = head;
    while(iter->next!=NULL){
        iter = iter->next;
    }
    iter->next = newnode;
}

void display(node *head){
    node *iter = head;
    while(iter!=NULL){
        printf("%d->",iter->data);
        iter = iter->next;
    }
    return;
}

int main(){
    node *head = NULL;
    int size;
    scanf("%d",&size);
    for(int i=0;i<size;i++){
        int value;
        scanf("%d",&value);
        push(head,value);
    }
    display(head);
}
c 指针 malloc singly-linked-list

评论

1赞 Fiddling Bits 8/14/2023
void push(node *head, int value)应该是 .您应该称它为 like 并访问它、in、with 等。void push(node **head, int value)push(&head,value);pushif(*head==NULL)
0赞 Harshit Singh 8/14/2023
@FiddlingBits你能解释一下为什么会发生这种情况吗,我的意思是在前面的方法中,指针应该指向新节点,但它不是一直指向 null。这两种方式不是一样,因为我们使用取消引用访问指针所指向的地址,所以它的意思是一样的。NVM:我明白了,谢谢伙计
2赞 Weather Vane 8/14/2023
将 的副本传递给函数,即其值。另一种方法是使用函数的值,例如 with 并用mainheadreturnnode *push(node *head,int value)return head;head = push(head,value);
0赞 AndreyKarpov 8/14/2023
在 C 语言中实现单向链表 - pvs-studio.com/en/blog/terms/6680

答:

1赞 Joel 8/14/2023 #1

你传入函数的是 ,它通过值传递(指针本身是按值传递的,指向的是通过引用/地址传递)传递给函数。这意味着您可以修改 is 指向,但不能指向其他内容(正确,您可以,但此更改仅在该函数调用期间持续,不会影响原始函数。headpush()node*nodepush()nodeheadheadheadmain()

因此,您需要将指针传递给 .然后,您的函数将如下所示:node*

void push(node** head, int value) {
    node* newnode = (node*)malloc(sizeof(node));
    newnode->data = value;
    newnode->next = NULL;
    printf("%d", value);
    if (*head == NULL) {
        *head = newnode;
        return;

    }
    node* iter = *head;
    while (iter->next != NULL) {
        iter = iter->next;
    }
    iter->next = newnode;
}

你会这样称呼它.push(&head, value);

0赞 Siva Nandu S 8/14/2023 #2

在程序中,您必须返回磁头或全局声明它。这是一个解决方案。

#include<stdio.h>
#include<stdlib.h>
typedef struct node{
    int data;
    struct node *next;
}   node;

node *push(node *head, int value){
    node *newnode = (node *)malloc(sizeof(node));
    newnode->data = value;
    newnode->next = NULL;
    printf("In the Push method : %d\n", value);
    if(head == NULL){
        head = newnode;
        return head;
    }
    node *iter = head;
    while(iter->next != NULL){
        iter = iter->next;
    }
    iter->next = newnode;
    return head;
}

void display(node *head){
    node *iter = head;
    while(iter != NULL){
        printf("%d->", iter->data);
        iter = iter->next;
    }
    return;
}

int main(){
    node *head = NULL;
    int size;
    printf("Enter the size of the linked list : ");
    scanf("%d", &size);
    for(int i = 0; i < size; i++){
        int value;
        printf("Enter the value : ");
        scanf("%d", &value);
        head = push(head, value);
    }
    display(head);
    return 0;
}

评论

3赞 Weather Vane 8/14/2023
你的“全局声明”不是一个好的解决方案,这个答案忽略了另一个解决方案,使用了其他地方详述的论点。否则看起来没问题。node **head
0赞 Siva Nandu S 8/14/2023
是的,我也不喜欢全局定义变量的做法,我支持您声明函数作为返回类型的建议。node **head
0赞 Weather Vane 8/14/2023
那不是返回类型,它仍然是 .它是参数类型。void
3赞 Vlad from Moscow 8/14/2023 #3

该函数处理 main 中定义的指针值的副本。更改函数中的副本会使原始指针保持不变。即函数参数,即函数的局部变量,由 main 中定义的指针头的值初始化,并用作参数表达式。pushheadhead

您需要通过引用将原始指针传递给函数。

在 C 语言中,通过引用传递意味着通过指向对象的指针间接传递对象。因此,取消引用指针,您可以直接访问原始对象。

该函数可以如下所示

int push( node **head, int value )
{
    node *newnode = malloc( sizeof( node ) );
    int success = newnode != NULL;

    if ( success )
    {
        newnode->data = value;
        newnode->next = NULL;

        while ( *head ) head = &( *head )->next;

        *head = newnode;
    } 

    return success;
}

该函数的调用方式如下

push( &head, value );

在函数中,您应该检查新节点的内存是否已成功分配。否则,该函数可以调用未定义的行为。

对于函数,则其参数应使用限定符声明,因为该函数不会更改列表的节点displayconst

void display( const node *head){

还要注意,将新节点添加到单向链表的末尾是低效的。最好定义一个双侧单向链表,其中包含指向列表开头及其最后一个节点的两个指针。

这可以通过定义另一个结构来实现,例如

typedef struct list
{
    struct node *head;
    struct node *tail;
} list;

在这种情况下,该函数可以如下所示push

int push( list *lst, int value )
{
    node *newnode = malloc( sizeof( node ) );
    int success = newnode != NULL;

    if ( success )
    {
        newnode->data = value;
        newnode->next = NULL;

        if ( lst->head == NULL )
        {
            lst->head = newnode;
        }
        else
        {
            lst->tail->next = newnode;
        }

        lst->tail = newnode;   
    } 

    return success;
}

functoin 在 main 中被称为

int main( void )
{
    list lst = { .head = NULL, .tail = NULL };
    
    push( &lst, 10 );

    // or

    if ( !push( &lst, 10 ) ) puts( "Error: not enough memory." );    

    //...
}