Thread: Print linked list: Error - segmentation fault

  1. #1
    Registered User
    Join Date
    Oct 2013
    Posts
    87

    Print linked list: Error - segmentation fault

    Code:
    struct node {
        int x;
        struct node *next;
        struct node *previous;
    }*start,*tail;
    
    void create(){
        int val=0;
        printf("We are to create new linked list. Enter number\n");
        scanf("%d",&val);
    
        if(start == NULL){
    
            start=malloc(sizeof(struct node*)); //create new
            start->next=start->previous=NULL; //make NULL 
            start->x=val;
    
        }else{
            struct node *temp=start; //create temp node
    
            while(temp!=NULL){ //this is the problem
                printf("The value is %d\n",temp->x);
                temp=temp->next;
            }
            struct node *new=malloc(sizeof(struct node *));
            new->next=NULL;
            new->previous=temp;
            temp->next=new;
            new->x=val;
    
        }
    
    }

    When I change:
    while(temp!=NULL)
    to
    while(temp->next!=NULL)

    I can easily traverse, and print through the list.
    If I don't change, I get error as:
    Segmentation fault (core dumped)

    I' unable to understand why this is occurring?
    Please guide.

  2. #2
    Programming Wraith GReaper's Avatar
    Join Date
    Apr 2009
    Location
    Greece
    Posts
    2,738
    Look at what you're doing after the while loop, at line #28.
    Devoted my life to programming...

  3. #3
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    This not only defines struct node, but also declares two global pointers:
    Code:
    struct node {
        int x;
        struct node *next;
        struct node *previous;
    }*start,*tail;
    However, global variables should be avoided, especially when you are a beginner, as they make it more difficult for your to reason about your program and hence to debug/maintain it. Rather, write:
    Code:
    struct node {
        int x;
        struct node *next;
        struct node *previous;
    };
    Then declare start and tail in main, or within some other function. You could also consider grouping them into a single struct, e.g.,
    Code:
    struct linked_list {
        struct node *start;
        struct node *tail;
    };
    Then declare a struct linked_list object or pointer in main or within some other function.

    Either way, your functions will then be changed to have appropriate parameters, thus allowing you to see more clearly what the functions operate on, and to reuse these functions more easily.
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  4. #4
    Registered User
    Join Date
    Oct 2013
    Posts
    87
    Quote Originally Posted by GReaper View Post
    Look at what you're doing after the while loop, at line #28.
    Hi GR,
    Thanks for your reply.
    I found one error:
    Code:
    struct node *new=malloc(sizeof(struct node *));
    should be changed to


    Code:
    struct node* new=malloc(sizeof(struct node));
    Next, at line 28, I made following changes:

    Code:
            temp=new;
            new->previous=temp;
            new->x=val;
    I don't get any crash error. It seems, I am not appending though.

  5. #5
    Registered User
    Join Date
    Oct 2013
    Posts
    87
    Hello laserlight,

    Quote Originally Posted by laserlight View Post
    This not only defines struct node, but also declares two global pointers:
    Code:
    struct node {
        int x;
        struct node *next;
        struct node *previous;
    }*start,*tail;
    Yes, to have them global was the purpose.

    Quote Originally Posted by laserlight View Post
    Then declare start and tail in main, or within some other function. You could also consider grouping them into a single struct, e.g.,
    Code:
    struct linked_list {
        struct node *start;
        struct node *tail;
    };
    I liked this idea. Thanks much.! http://cboard.cprogramming.com/images/smilies/smile.png

  6. #6
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    Allow me to expand on my suggestions in post #3:
    Code:
    /* ... */
    
    struct node {
        int x;
        struct node *next;
        struct node *previous;
    };
    
    struct linked_list {
        struct node *start;
        struct node *tail;
    };
    
    struct node *append_node(struct linked_list *list, int value) {
        struct node *new_node = malloc(sizeof(*new_node));
        if (new_node) {
            new_node->x = value;
            new_node->next = NULL;
    
            if (list->start) {
                new_node->previous = list->tail;
                list->tail->next = new_node;
                list->tail = new_node;
            } else {
                new_node->previous = NULL;
                list->start = new_node;
                list->tail = new_node;
            }
        }
        return new_node;
    }
    
    void create_list(struct linked_list *list) {
        int val = 0;
        printf("We are to create new linked list. Enter number\n");
        if (scanf("%d", &val) == 1) {
            struct node *temp = append_node(list, val);
            if (temp) {
                printf("The value is %d\n", temp->x);
            } else {
                /* Could not append node, so report or otherwise handle the error */
            }
        } else {
            /* Invalid input, so report or otherwise handle the error */
        }
    }
    
    /* ... */
    
    int main(void) {
        struct linked_list list = {NULL};
        create_list(&list);
        /* ... */
        return 0;
    }
    Doing it this way, you separate the logic of appending a node from the logic of doing interactive I/O and actually building the linked list.

    I have taken the liberty of implementing append_node for you as it looks like you did put in effort to think about and implement the logic as per post #1. Notice that:
    • Instead of calling malloc in two places like you did, I did it in just one place and did the check for a null pointer before proceeding.
    • Instead of setting the new node's value and next pointer in two places like you did, I did it in just one place once it is known that malloc did not return a null pointer.
    • Instead of doing a loop to find the tail, I just used the tail pointer.
    • Since I separated append_node from create_list, I made it such that create_list (and other functions that might use append_node) can check if append_node succeeded.

    Also, while you did correctly fix the malloc call to:
    Code:
    struct node* new=malloc(sizeof(struct node));
    Using this instead:
    Code:
    struct node *new_node = malloc(sizeof(*new_node));
    avoid having to check that you did use the correct type.

    By the way, I think that it is conventional to use head and tail rather than start and tail. If you do want to use start, I would expect start and end. (There's also start and stop as well as start and finish, but those probably would be unconventional for linked lists.)
    Last edited by laserlight; 08-10-2015 at 11:48 AM.
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  7. #7
    Registered User
    Join Date
    Oct 2013
    Posts
    87
    Hello laserlight,

    I didn't want to trouble you for the code. I know, it was a cake walk, for you're an expert.

    I was/am interested to fix the glitch/but in my code.

    Quote Originally Posted by laserlight View Post

    • Instead of calling malloc in two places like you did, I did it in just one place and did the check for a null pointer before proceeding.
    • Instead of setting the new node's value and next pointer in two places like you did, I did it in just one place once it is known that malloc did not return a null pointer.
    Yes, I should have made it more modular, avoided using twice malloc. And keep one function to return node. Also, a check is a must (I'm learning this part).

    Quote Originally Posted by laserlight View Post
    Also, while you did correctly fix the malloc call to:

    Code:
    struct node* new=malloc(sizeof(struct node));
    Using this instead:

    Code:
    struct node *new_node = malloc(sizeof(*new_node));
    avoid having to check that you did use the correct type.
    >> I didn't quite understand what you imply here, my lack of knowledge is to be held culprit here.

    struct node* temp = malloc(sizeof(struct node))
    V/s
    struct node *temp = malloc(sizeof(*temp))


    How do I decide which one to use, when and why?


    Thank you again for your constant support, guidance, time and reply.

  8. #8
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    Quote Originally Posted by deathmetal
    I was/am interested to fix the glitch/but in my code.
    GReaper pointed out where the error would have manifested, but the mistake was earlier in the code: you terminated the loop when temp is a null pointer, so consequently you cannot dereference temp. To fix this, you should not fix line 28, but rather you should fix the loop such that temp points to the tail node. Hence, your solution to do this works:
    Code:
    while(temp->next!=NULL)
    But of course it is more efficient to just use the tail pointer.

    Quote Originally Posted by deathmetal
    >> I didn't quite understand what you imply here, my lack of knowledge is to be held culprit here.

    struct node* temp = malloc(sizeof(struct node))
    V/s
    struct node *temp = malloc(sizeof(*temp))


    How do I decide which one to use, when and why?
    They are equivalent, but unless temp is a pointer to void, you should use the latter.

    The problem with the former is that you could have written, and in fact did write:
    Code:
    temp = malloc(sizeof(struct node*));
    and it is easy to miss this, since it looks almost correct and the compiler will not complain. With this:
    Code:
    temp = malloc(sizeof(*temp));
    It is clear that the idea is to allocate space for one object of what temp would point to. This would only be a problem if temp is a pointer to void, but at a high enough warning level a compiler is likely to complain.
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  9. #9
    Registered User
    Join Date
    Oct 2013
    Posts
    87
    Quote Originally Posted by laserlight View Post
    you terminated the loop when temp is a null pointer, so consequently you cannot dereference temp. To fix this, you should not fix line 28, but rather you should fix the loop such that temp points to the tail node.
    Yep, I realized the error after a small break.
    If the iterator (temp in this case) is NULL, how would it be able to point to anything?

    Thank you for the detailed description for different pointer concepts.

    Best,
    deathmetal

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Segmentation fault in linked list program
    By smrtshrm in forum C Programming
    Replies: 5
    Last Post: 06-26-2015, 06:00 AM
  2. Segmentation Fault -- Stack implementing a Linked List
    By jackalclone1 in forum C Programming
    Replies: 10
    Last Post: 02-15-2014, 12:44 AM
  3. Segmentation fault in linked list...doubt
    By alphasil in forum C Programming
    Replies: 17
    Last Post: 07-11-2012, 05:23 PM
  4. Doubly linked list-segmentation fault
    By prapanch in forum C Programming
    Replies: 2
    Last Post: 05-10-2012, 11:04 PM
  5. Doubly Linked List Segmentation Fault
    By DaNxTh3xMaNx in forum C Programming
    Replies: 5
    Last Post: 09-09-2011, 09:50 AM

Tags for this Thread