0
votes

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_. It is copied in the function but the side effect isn´t working. In my main-function the value is still 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?

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

2
Does this answer your question? Changing address contained by pointer using functionkaylum

2 Answers

0
votes

kaylum's comment points you in the right direction.

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. 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;
    }
0
votes

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

struct list *l = NULL;

Or the function initialize can look like

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

The function add_element deals with a copy of the passed list.

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.

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.