简体   繁体   English

复制指向函数中结构体的指针(链表)

[英]Copy a pointer to a struct in a function (linked list)

I want to craete a single linked list without gloabal variables.我想创建一个没有全局变量的单链表。 I initialized the first element with NULL and then wanted to copy the first element node to list_ .我用NULL初始化了第一个元素,然后想将第一个元素node复制到list_ It is copied in the function but the side effect isn´t working.它被复制到函数中,但副作用不起作用。 In my main-function the value is still NULL .在我的主函数中,该值仍然是NULL If I return the struct in the add_element() function all works fine but, is it possible that l gets the value of node without changing the functions structure and the struct itself?如果我在返回结构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;
}

kaylum's comment points you in the right direction. kaylum 的评论为您指明了正确的方向。

When you pass a pointer in C, the pointer's value is copied to the stack, and this copy is the value that the add_element() function is referring to.当你在 C 中传递一个指针时,指针的值被复制到堆栈中,这个副本就是add_element()函数所引用的值。 When you alter the pointer's value, you are modifying the copy placed on the stack, not the original pointer .当您更改指针的值时,您正在修改放置在堆栈上的副本,而不是原始指针

If you want to alter the original pointer (as if it was passed by reference and not by value) you need to use a double pointer.如果要更改原始指针(就像它是通过引用而不是通过值传递一样),则需要使用双指针。

Try this variant:试试这个变体:

    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;
    }

For starters the function initialize对于初学者,函数初始化

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

does not make great sense.没有多大意义。 You can just write in main你可以写在 main

struct list *l = NULL;

Or the function initialize can look like或者函数initialize看起来像

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

The function add_element deals with a copy of the passed list.函数add_element处理传递列表的副本。

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

So any changes of the copy do not influence on the original list.因此,副本的任何更改都不会影响原始列表。 Also it is unclear why the second parameter has the type void * instead of the type int .也不清楚为什么第二个参数的类型是void *而不是类型int

You have to pass the list by reference to the function.您必须通过引用函数来传递列表。

The function can look the following way该函数可以如下所示

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;
}

and called for example like并调用例如

int i = 10;

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

Here is a demonstrative program这是一个演示程序

#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;
}

Its output is它的输出是

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

Pay attention to that if a new node is appended to the tail of the list then it is better to define the list as a two-sided singly-linked list.注意,如果一个新节点被附加到链表的尾部,那么最好将链表定义为双边单向链表。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM