Search code examples
clinked-listdynamic-memory-allocationsingly-linked-listfunction-definition

How to properly allocate memory for linked list in C inside function?


I have spent several hours trying to initialize linked list with, say, integer values from 0 to 10. I create pointer of struct node and pass its reference to function init_ll. The init_ll function should initialize 10 elements of linked list. But it seems only first memory allocation works, because I get liked list with only one element.

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

#define N 10

typedef struct node {
    int value;
    struct node *next;
} node_t;

void init_ll(node_t **head, int n)
{
    // allocate memory for the first node
    node_t *p= (node_t *)malloc(sizeof(node_t));
    // copy the address of the first node to head
    *head = p;

    // initialize first node value
    p->value = 0;
    p = p->next;

    // initialize the reamining nodes
    for (int i=1; i<n; i++) {
        p = (node_t *)malloc(sizeof(node_t));
        p->value = i;
        p= p->next;
    }
    p = NULL;
}

int main(void)
{
    node_t *head;
    init_ll(&head, 10);

    return 0;
}

It seems I misunderstand some conception about memory-scope. I will be grateful if someone provide a proper example of allocation memory for linked list inside function. All I have found so far were examples of allocation of memory in main function.


Solution

  • For starters it would be more correctly and clear to write in main

    node_t *head = NULL;
    

    Within the function you are not initializing data members next of created nodes. They have indeterminate values. So this statement

    p = p->next;
    

    does not make sense. And moreover the pointer p is overwritten in the for loop

    p = (node_t *)malloc(sizeof(node_t));
    

    Also pay attention to that you are changing the local variable (pointer) p that is not linked with the list.

    And the behavior pf the function will be incorrect if the user will pass a negative value as the second argument.

    The function can be declared and defined the following way

    size_t init_ll( node_t **head, size_t n )
    {
        while ( *head )
        {
            node_t *tmp = *head;
            *head = ( *head )->next;
            free( tmp );
        }
    
        size_t cnt = 0;
    
        for ( int success = 1; success && cnt < n; cnt++ )
        {
            *head = malloc( sizeof( node_t ) );
    
            if ( ( success = *head != NULL ) )
            {
                ( *head )->value = cnt;
                ( *head )->next  = NULL;
                head = &( *head )->next;
            }
        }
    
        return cnt;
    }
    

    This while loop

    while ( *head )
    {
        node_t *tmp = *head;
        *head = ( *head )->next;
        free( tmp );
    }
    

    you could form as a separate function. For example

    void clear( node_t **head )
    {
        while ( *head )
        {
            node_t *tmp = *head;
            *head = ( *head )->next;
            free( tmp );
        }
    }
    

    In this case the original function will look like

    size_t init_ll( node_t **head, size_t n )
    {
        clear( head );
    
        size_t cnt = 0;
    
        for ( int success = 1; success && cnt < n; cnt++ )
        {
            *head = malloc( sizeof( node_t ) );
    
            if ( ( success = *head != NULL ) )
            {
                ( *head )->value = cnt;
                ( *head )->next  = NULL;
                head = &( *head )->next;
            }
        }
    
        return cnt;
    }
    

    Also the defined macro name N

    #define N 10
    

    is not used in your program. So its presence in the program is unclear and it seems does not make sense.