Thread: Linked lists

  1. #1
    Registered User
    Join Date
    Sep 2013
    Posts
    82

    Linked lists

    Hello, I went through three articles about linked lists, but I am just not getting how the whole thing works. I have written a code, but it's not working:
    Code:
    #include<stdio.h>
    
    struct node
    {
           int   x;
           struct node *next;
    };
    
    int main(void)
    {
        int i;
        struct node *head;
        struct node *ptr;
        
        head = malloc(sizeof(struct node));
        ptr = head;
        
        for(i = 0; i < 3; i++)
        {
              scanf(" %d",ptr->x);
              ptr = ptr->next;
        }
        
        ptr = head;
        while(ptr != NULL)
        {
             printf("%d\n",ptr->x);
             ptr = ptr->next;
        }
        
        system("pause");
        return 0;
    }
    Please guys I need help to understand linked lists better, please help me out.

  2. #2
    Registered User
    Join Date
    Jun 2005
    Posts
    6,815
    To use any data structure, it is necessary to initialise it. To use a linked list it is necessary to both allocate each node, and to initialise every node.

    Your code only allocates a single struct, and does not initialise it. The last loop then walk over the list as if all of the structs have been allocated (which, other than head, they haven't) and initialised. Accessing the value of an uninitialised anything (an int, a pointer) gives undefined behaviour.

    malloc() does not initialise the memory it allocates. And it only allocates the memory asked for (for a single struct in your code) no more.

    To use malloc() it is necessary to #include <stdlib.h>.

    You really should check that malloc() succeeds. It returns NULL if it fails.

    No, I'm not going to give you code. Work out how to translate the hints I've given you about your mistakes into working code.
    Right 98% of the time, and don't care about the other 3%.

    If I seem grumpy or unhelpful in reply to you, or tell you you need to demonstrate more effort before you can expect help, it is likely you deserve it. Suck it up, Buttercup, and read this, this, and this before posting again.

  3. #3
    Registered User
    Join Date
    Jun 2011
    Posts
    4,513
    It seems you're on the right track, but your code is incomplete. You're only allocating space for one node (the head pointer), then trying to move up a list that doesn't exist.

    Try implementing the following steps:

    - allocate memory for the head node (which you've done)
    - initialize the members ("struct node *next" should be set to NULL)

    To add a second node:

    - allocate memory for another node (pointer)
    - initialize the members ("struct node *next" should be set to NULL)
    - set the "next" pointer in "head" to point to the newly created node

    To add more nodes:

    - find the last valid node (starting at "head", transverse the pointers until you find the node that has the "next" pointer set to NULL)
    - allocate memory for another node (pointer)
    - initialize the members ("struct node *next" should be set to NULL)
    - set the "next" pointer in the node found above to point to the newly created node

    And don't forget to free your memory when you're finished!

  4. #4
    Registered User
    Join Date
    Nov 2010
    Location
    Long Beach, CA
    Posts
    5,909
    Your problem is in how you build the list, your print code looks fine. You never set head->x or head->next, so your first node is useless, and you can't use head->next (or ptr->next since head and ptr point to the same place) until it points to valid memory. You need to malloc every node you create and set the next element to something useful, either the next node you create, or NULL to signify end of list. Also, when you do your loop on lines 18-22, you use ptr->next, but you only allocated the first node, so you've walked off the end of the list. It's a bit like walking off the end of an array: you have started to access memory you don't own, and thus you are experiencing undefined behavior. The last problem is that you aren't calling scanf properly. You need a pointer to where you are storing the data, i.e. use the address-of operator (ampersand) &(ptr->x). What you need to do is something like the following:
    Code:
    head = malloc
    // read data into head->x
    ptr = head
    for i from 0 to 2
        ptr->next = malloc  // allocate a new node and make it the next node in the list
        ptr = ptr->next;  // make ptr point to this new node
        scanf("%d", &(ptr->x));
    
    ptr->next = NULL;  // terminate the list

  5. #5
    Registered User
    Join Date
    Sep 2013
    Posts
    82
    Quote Originally Posted by anduril462 View Post
    Your problem is in how you build the list, your print code looks fine. You never set head->x or head->next, so your first node is useless, and you can't use head->next (or ptr->next since head and ptr point to the same place) until it points to valid memory. You need to malloc every node you create and set the next element to something useful, either the next node you create, or NULL to signify end of list. Also, when you do your loop on lines 18-22, you use ptr->next, but you only allocated the first node, so you've walked off the end of the list. It's a bit like walking off the end of an array: you have started to access memory you don't own, and thus you are experiencing undefined behavior. The last problem is that you aren't calling scanf properly. You need a pointer to where you are storing the data, i.e. use the address-of operator (ampersand) &(ptr->x). What you need to do is something like the following:
    Code:
    head = malloc
    // read data into head->x
    ptr = head
    for i from 0 to 2
        ptr->next = malloc  // allocate a new node and make it the next node in the list
        ptr = ptr->next;  // make ptr point to this new node
        scanf("%d", &(ptr->x));
    
    ptr->next = NULL;  // terminate the list
    Thanks man. I looked everywhere but your code is much better to understand. Here's my new code:
    Code:
    #include<stdio.h>
    
    struct node
    {
           int   x;
           struct node *next;
    };
    
    int main(void)
    {
        int i;
        struct node *head = NULL;
        struct node *ptr = NULL;
        
        head = malloc(sizeof(struct node));
        ptr = head;
        
        for(i = 0; i < 3; i++)
        {
              ptr->x = i;
              ptr->next = malloc(sizeof(struct node));
              ptr = ptr->next;
        }
        
        ptr->next = NULL; //why 'ptr = NULL;' is not working?
        ptr = head;
        while(ptr != NULL)
        {
             printf("%d\n",ptr->x);
             ptr = ptr->next;
        }
        
        system("pause");
        return 0;
    }
    There's a problem, its last value is gibberish.
    linked lists is some real challenge now
    Last edited by Harith; 10-03-2013 at 07:49 AM.

  6. #6
    Registered User
    Join Date
    Nov 2010
    Location
    Long Beach, CA
    Posts
    5,909
    In the loop, ptr->next is allocated, then ptr is moved to the new node. When the loop is over, if you do ptr = NULL, you are making ptr point to NULL instead of the last node. You are not changing the last node that way. What you want to do is set the last node's next element to NULL, to indicate there are no more nodes after the last one. So yes, after your loop to create the list, you should do
    Code:
    ptr->next = NULL;

  7. #7
    Registered User
    Join Date
    Sep 2013
    Posts
    82
    Quote Originally Posted by anduril462 View Post
    In the loop, ptr->next is allocated, then ptr is moved to the new node. When the loop is over, if you do ptr = NULL, you are making ptr point to NULL instead of the last node. You are not changing the last node that way. What you want to do is set the last node's next element to NULL, to indicate there are no more nodes after the last one. So yes, after your loop to create the list, you should do
    Code:
    ptr->next = NULL;
    Ya, but when I am printing the values, its printing 4 values and last one is printing a garbage value.

  8. #8
    Registered User
    Join Date
    Nov 2010
    Location
    Long Beach, CA
    Posts
    5,909
    Quote Originally Posted by Harith View Post
    Ya, but when I am printing the values, its printing 4 values and last one is printing a garbage value.
    Ahh, I see what you're saying now. Notice, you changed my code a little (which is okay), but you didn't consider all the ramifications. We initialize the x member in different places. My code fills head->x before the loop, then fills ptr->x after malloc'ing and doing ptr = ptr->next. Your code fills the x element before moving to the next node, so you don't need to fill the first element before the loop, but you do need to fill the last element after the loop.

  9. #9
    Registered User
    Join Date
    Jun 2011
    Posts
    4,513
    It's because you assign data to the current node then create a new node each iteration of the loop. So the last time through the loop, the last node you've created isn't given a value.

    Code:
    // Before loop, "head" is created
    
     +-----+
     | [ ] |
     |     |
     |  *  |
     +-----+
    
    // During loop:
    
    // i = 0, you assign data to the current node and create a new node
    
     +-----+    +-----+
     | [0] |    | [ ] |
     |     |    |     |
     |  *--|--->|  *  |
     +-----+    +-----+
                 (new)
    
    // i = 1, you assign data to the current node and create a new node
    
     +-----+    +-----+    +-----+
     | [0] |    | [1] |    | [ ] |
     |     |    |     |    |     |
     |  *--|--->|  *--|--->|  *  |
     +-----+    +-----+    +-----+
                            (new)
    
    // i = 2, you assign data to the current node and create a new node
    
     +-----+    +-----+    +-----+    +-----+
     | [0] |    | [1] |    | [2] |    | [ ] |
     |     |    |     |    |     |    |     |
     |  *--|--->|  *--|--->|  *--|--->|  *  |
     +-----+    +-----+    +-----+    +-----+
                                       (new)
    
    // you break out of the loop, and assign NULL to the last node, which was never given data
    
     +-----+    +-----+    +-----+    +-----+
     | [0] |    | [1] |    | [2] |    | [ ] |
     |     |    |     |    |     |    |     |
     |  *--|--->|  *--|--->|  *--|--->|  *--|--->NULL
     +-----+    +-----+    +-----+    +-----+

  10. #10
    Registered User
    Join Date
    Apr 2013
    Posts
    1,658
    If the next pointer is the first member of a node, then *(node->next) is the same as **(node), since the address of the first member of a structure is the same as the address of the structure in C / C++. This allows the initialization code to be simplified by setting the temp ptr = &head. I changed node to be a typedef, and added code to free the allocated nodes as they are displayed:

    Code:
    #include <stdio.h>
    #include <stdlib.h>
    
    typedef struct _node
    {
        struct _node *next;
        int x;
    }node;
    
    int main(void)
    {
        int i;
        node *head = NULL;
        node *ptr = (node *)&head;
        node *tmp;
        
        for(i = 0; i < 3; i++)
        {
            ptr->next = malloc(sizeof(node));
            ptr = ptr->next;
            ptr->x = i;
        }
        ptr->next = NULL;
    
        ptr = head;
        while(ptr != NULL)
        {
            printf("%d\n",ptr->x);
            tmp = ptr;
            ptr = ptr->next;
            free(tmp);
        }
        
        system("pause");
        return 0;
    }
    Last edited by rcgldr; 10-03-2013 at 11:01 AM.

  11. #11
    Registered User
    Join Date
    Sep 2013
    Posts
    82
    Quote Originally Posted by Matticus View Post
    It's because you assign data to the current node then create a new node each iteration of the loop. So the last time through the loop, the last node you've created isn't given a value.

    Code:
    // Before loop, "head" is created
    
     +-----+
     | [ ] |
     |     |
     |  *  |
     +-----+
    
    // During loop:
    
    // i = 0, you assign data to the current node and create a new node
    
     +-----+    +-----+
     | [0] |    | [ ] |
     |     |    |     |
     |  *--|--->|  *  |
     +-----+    +-----+
                 (new)
    
    // i = 1, you assign data to the current node and create a new node
    
     +-----+    +-----+    +-----+
     | [0] |    | [1] |    | [ ] |
     |     |    |     |    |     |
     |  *--|--->|  *--|--->|  *  |
     +-----+    +-----+    +-----+
                            (new)
    
    // i = 2, you assign data to the current node and create a new node
    
     +-----+    +-----+    +-----+    +-----+
     | [0] |    | [1] |    | [2] |    | [ ] |
     |     |    |     |    |     |    |     |
     |  *--|--->|  *--|--->|  *--|--->|  *  |
     +-----+    +-----+    +-----+    +-----+
                                       (new)
    
    // you break out of the loop, and assign NULL to the last node, which was never given data
    
     +-----+    +-----+    +-----+    +-----+
     | [0] |    | [1] |    | [2] |    | [ ] |
     |     |    |     |    |     |    |     |
     |  *--|--->|  *--|--->|  *--|--->|  *--|--->NULL
     +-----+    +-----+    +-----+    +-----+
    So how do I assign null to 2nd node?

  12. #12
    Registered User
    Join Date
    Apr 2013
    Posts
    1,658
    Quote Originally Posted by Harith View Post
    So how do I assign null to 2nd node?
    See post #10, for an alternative way to initialize the list that eliminates having to special case the initialization of head and the first node.

  13. #13
    Registered User
    Join Date
    Jun 2011
    Posts
    4,513
    So how do I assign null to 2nd node?
    Try restructuring your logic - it seems backwards. In the loop, you (1) assign data to current node, then (2) create a new node. Instead, consider (1) creating a new node, then (2) assigning data to it.

    Right now, your code does this:

    Code:
     - Create head node
     - In loop:
       - Assign data to the current node
       - Create a new node
    It would be better to do something like:

    Code:
     - Create and initialize head node
     - In loop:
       - Create a new node
       - Assign data to the current node (this is where the "next" pointer of the last valid node is set to NULL, before breaking out of the loop)
    rcgldr has some good advice you should consider. My suggestion might be easier for you to implement with what you have so far, for the purposes of understanding.

  14. #14
    Registered User
    Join Date
    Jun 2011
    Posts
    4,513
    Oh, and if you haven't already, grab a pencil and paper draw out the linked list based on your code, line by line (which I sort of did in post #9). I personally prefer the representation I illustrated. For me, the understanding of linked lists did not come from code, but from the illustrations of how a linked list was supposed to work. Any code I wrote was simply a result of that understanding.

  15. #15
    Registered User
    Join Date
    Sep 2013
    Posts
    82
    Thanks guys for the help.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Double Linked Dynamic Lists Vs Unrolled Linked Lists
    By lantzvillian in forum C Programming
    Replies: 6
    Last Post: 02-14-2012, 01:07 PM
  2. Replies: 4
    Last Post: 05-01-2010, 10:19 PM
  3. Question about Linked lists of lists
    By hear_no_evil in forum C Programming
    Replies: 2
    Last Post: 11-08-2004, 02:49 AM
  4. question on linked lists(stack with linked lists)
    By dionys in forum C Programming
    Replies: 1
    Last Post: 06-02-2004, 11:08 AM
  5. Linked List of Linked lists Revisited.
    By Qui in forum C++ Programming
    Replies: 11
    Last Post: 04-11-2004, 09:45 PM

Tags for this Thread