max kremsner
max kremsner

Reputation: 23

Segmentation Fault with C List when not using global List

I have written some code creating a singly linked list and then converting it to a dynamic array in C.

The code works just fine if I only create a global variable for the list header. If I want to create the list in my main function, however, I always get a segmentation fault.

The code below works just fine as soon as I create a global list variable instead and remove the list as parameter from all functions.

Can anyone tell me why this won't work if I want to pass the list as a parameter to the function and thus be able to create multiple lists?


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

typedef struct NodeStruct* Node;
typedef struct NodeStruct {
Node next;
int val;
} NodeStruct;
typedef Node List;



Node newNode(int x){
    Node n = (Node)malloc(sizeof(NodeStruct));
    if(n!=NULL){
        n->val = x;
        n->next = NULL;
        return n;
    }
    else{
        printf("ERROR: Could not allocate memory!\n");
    }
    exit(1);
}

void prepend(List l, Node node){
    if (l == NULL) l = node;
    else{
        node->next = l;
        l = node;
    }
}

void printList(List l){
    if(l!=NULL){
        Node n = l;
        while(n->next != NULL){
            printf("%d, ", n->val);
            n = n->next;
        }
        printf("%d\n", n->val);
    }
    else{
        printf("ERROR: List empty!\n");
    }
}



/*=============================*/

int* arrOf(List l){
    if(l==NULL){
        printf("ERROR: List empty\n");
        exit(1);
    }

    int size = 0;
    Node n = l;
    while(n!=NULL){
        size++; 
        n = n->next;
    }
    
    int* arr = (int*)malloc((size+1)*sizeof(int));
    n = l;
    int i = 0;
    arr[i++] = size;
    while(n != NULL){
        arr[i++] = n->val;
        n = n->next;
    }
    printf("Returning Array\n");
    return arr;
}



int main(int argc, char *argv[]){

    List l;
    
    prepend(l, newNode(5));
    prepend(l, newNode(6));
    prepend(l, newNode(7));
    prepend(l, newNode(8));
    prepend(l, newNode(9));
    prepend(l, newNode(4));
   
    printList(l);
    printf("\n===========================================\n");
    
    int* arr = arrOf(l);
    for(int i = 0; i < 10; ++i){
        printf("%d, ", arr[i]);
    }

    return 0;
}

Upvotes: 1

Views: 123

Answers (2)

Vlad from Moscow
Vlad from Moscow

Reputation: 311048

This function

void prepend(List l, Node node){
    if (l == NULL) l = node;
    else{
        node->next = l;
        l = node;
    }
}

deals with a copy of the value of the pointer l declared in main

List l;

that moreover was not initialized.

So changing of the copy in these statements within the function

if (l == NULL) l = node;
//...
l = node;

does not influence on the original value of the pointer declared in main.

You have to write at least like

void prepend(List *l, Node node){
        node->next = *l;
        *l = node;
}

and in main

List l = NULL;

The function can be called like

prepend( &l, newNode(5) );

That is the pointer to the head node must be passed to the function by reference.

Also you need to free all the dynamically allocated memory for the list and the array.

Upvotes: 1

Martin Fink
Martin Fink

Reputation: 1931

When you initialize List l in main, you are not assigning a default value. It is stored on the stack and not initialized. This means the value is undefined and not necessarily null.

When you are creating List l globally, the variable is stored in the bss segment and initialized with null.

Change your declaration of List l to:

List l = NULL;

Upvotes: 2

Related Questions