0

我想创建一个没有全局变量的单链表。我用初始化第一个元素,NULL然后想将第一个元素复制nodelist_. 它被复制到函数中,但副作用不起作用。在我的主要功能中,价值仍然是NULL. 如果我在函数中返回结构add_element()一切正常但是,是否有可能l在不更改函数结构和结构本身的情况下获取节点的值?

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

struct list {
        int value;
        struct list *next;
};


struct list *initialize(void)
{
    struct list * l = NULL;
    return l;
}

int add_element(struct list *list_, void *v)
{
    struct list *node = malloc(sizeof(struct list));
    node->value = *((int*)v);
    node->next = NULL;

    if(list_ == NULL)
    {
        list_ = node;
        printf("list_->value = %d\n", list_->value);    // correct copy
        return 0;
    }
    //TODO if not first then  add at end..
    return 0;
}

int main()
{
    struct list *l = initialize(); // l = NULL
    int i = 10;
    add_element(l,&i);
    if(l == NULL) printf("l == NULL!\n");
    printf("l->value = %d\n", l->value); // does not work, l is NULL
    return 0;
}

4

2 回答 2

0

对于初学者,函数初始化

struct list *initialize(void)
{
    struct list * l = NULL;
    return l;
}

没有多大意义。你可以写在 main

struct list *l = NULL;

或者函数initialize看起来像

inline struct list *initialize(void)
{
    return NULL;
}

该函数add_element处理传递列表的副本。

int add_element(struct list *list_, void *v);

因此副本的任何更改都不会影响原始列表。也不清楚为什么第二个参数有 typevoid *而不是 type int

您必须通过引用函数来传递列表。

该功能可以如下所示

int add_element( struct list **head, int value )
{
    struct list *node = malloc( sizeof( struct list ) );
    int success = node != NULL;

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

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

        *head = node;
    }

    return success;
}

并称为例如

int i = 10;

if ( !add_element( &l, i ) )
{
    puts( "Error: not enough memory." );
}

这是一个演示程序

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

struct list 
{
    int value;
    struct list *next;
};

static inline struct list * initialize( void )
{
    return NULL;
}

int add_element( struct list **head, int value )
{
    struct list *node = malloc( sizeof( struct list ) );
    int success = node != NULL;

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

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

        *head = node;
    }

    return success;
}

void output( struct list *head )
{
    for ( ; head != NULL; head = head->next )
    {
        printf( "%d -> ", head->value );
    }

    puts( "NULL" );
}

int main(void) 
{
    struct list *head = initialize();

    const int N = 10;

    for ( int i = 0; i < N; i++ )
    {
        add_element( &head, i );
    }

    output( head );

    return 0;
}

它的输出是

0 -> 1 -> 2 -> 3 -> 4 -> 5 -> 6 -> 7 -> 8 -> 9 -> NULL

请注意,如果一个新节点附加到列表的尾部,那么最好将列表定义为双边单链表。

于 2020-01-22T21:45:08.397 回答
0

kaylum 的评论为您指明了正确的方向。

当你在 C 中传递一个指针时,指针的值被复制到堆栈中,这个副本就是add_element()函数所引用的值。当您更改指针的值时,您正在修改放置在堆栈上的副本,而不是原始指针

如果要更改原始指针(就好像它是通过引用而不是通过值传递),则需要使用双指针。

试试这个变种:

    int add_element(struct list **list_, void *v)
    {
        struct list *node = malloc(sizeof(struct list));
        node->value = *((int*)v);
        node->next = NULL;

        if(*list_ == NULL)  // dereferencing the double pointer will access the original pointer
        {
            *list_ = node;  // this will change the original pointer
            printf("(*list_)->value = %d\n", (*list_)->value);    // correct copy
            return 0;
        }
        //TODO if not first then  add at end..
        return 0;
    }

    int main()
    {
        struct list *l = initialize(); // l = NULL  
        int i = 10;
        add_element(&l,&i); // notice you are now passing the address of l instead of its value
        if(l == NULL) printf("l == NULL!\n");
        printf("l->value = %d\n", l->value); //should work now
        return 0;
    }
于 2020-01-22T21:37:45.377 回答