Thread: Simplifying a simple linked list with a search function.

  1. #1
    Registered User
    Join Date
    Oct 2012
    Posts
    42

    Simplifying a simple linked list with a search function.

    Code:
    #include <stdlib.h>
    #include <string.h>
    #include <stdio.h>
     
    struct node
    {
            int data;
            struct node *next;
    };
     
    typedef struct node link;
    link *searchList(int value, link *head);
     
    int main()
    {
            struct node *first, *current, *temp;
            first = calloc(1, sizeof(struct node));
            current = first;
            int i = 0;
            for (i = 0; i < 9; i++)
            {
                    temp = calloc(1, sizeof(struct node));
                    temp->data = i;
                    current->next = temp;
                    current = current->next;
            }
            current = first->next;
            printf("Printing node values...\n");
            while (current)
            {
                    printf("%d\n", current->data);
                    current = current->next;
            }       
            int search = 0;
            printf("-----------------\n");
            printf("Please enter a value to search for: ");
            scanf("%d", &search);
            current = first->next;
            printf("[%d %d]\n", search, searchList(search, first)->data);
            printf("(if the function returns [(value that's not 0) 0], it means that the term you searched for was not found)\n");
    
            current = first->next;
            while (current)
            {
                    free(current);
                    current = current->next;
            }
            free(first);
            return 0;
    }
     
    
    link *searchList(int value, link *head)
    {
            struct node *temp;
            temp = head;
    
            while(head)
            {
    
                    if(value == head->data)
                    {
    
                            return head;
                    }
                    head = head->next;
            }
            head = temp;
            return head;
    }
    It fills the singly-linked list with 0 through 9 and calls a function to prompt the user to search for a number. I don't see any glaring errors, I was just wondering what could be done to simplify it or if there's anything I missed.

  2. #2
    Registered User
    Join Date
    Aug 2005
    Location
    Austria
    Posts
    1,990
    Code:
            while (current)
            {
                    free(current);
                    current = current->next;
            }
    This is undefined behaviour.
    You assign current from next of a node that is already deleted.

    You need a temporary
    e.g.
    Code:
            struct node * tmp;
            while (current)
            {
                    tmp = current->next;
                    free(current);
                    current = tmp;
            }
    Kurt

  3. #3
    Registered User migf1's Avatar
    Join Date
    May 2013
    Location
    Athens, Greece
    Posts
    385
    Quote Originally Posted by Paul Omans View Post
    ...
    It fills the singly-linked list with 0 through 9 and calls a function to prompt the user to search for a number. I don't see any glaring errors, I was just wondering what could be done to simplify it or if there's anything I missed.
    It depends on how you define simplicity. For me, for example, usage of functions results in a much more simplified & readable main() ...

    Code:
    int main( void )
    {
        Node *list = NULL;
        Node *p = NULL;
        int i;
    
        for (i=0; i < 9; i++)
        {
            if ( !list_append(&list, i) ) {
                fputs( "*** possible memory shortage\n", stderr );
                list_free( &list );
                return 1;
            }
        }
    
        puts("Printing node values...");
        list_print( list );
    
        puts("-----------------");
        printf("Please enter a value to search for: ");
        fflush( stdout );
        scanf("%d", &i);
    
        p = list_search( list, i );
        printf( "%d was %sfound in the list\n", i, (p ? "\0" : "not ") );
    
        list_free( &list );
    
        return 0;
    }
    It also results in a much more maintainable and scalable code.

    If this is not a homework, and you are interested, I could show the implementations of the functions I used up there (although they are considered trivial and they are available all over the Internet).
    Last edited by migf1; 06-05-2013 at 01:40 PM. Reason: replaced some printf() with puts()

  4. #4
    Registered User
    Join Date
    Apr 2013
    Posts
    1,658
    The program uses a head or dummy node, but calls it "first". You could pick a better variable name for "first", such as "head" or "dummy".

    I prefer to put the pointers for nodes first in structures. This would allow generic list routines to be used with multiple node types (with the proper casting). It's not needed for your search program, since it only has one node type.

    Code:
    struct node{
        struct node * next;
        int data;
    }
    Last edited by rcgldr; 06-05-2013 at 02:22 PM.

  5. #5
    Registered User
    Join Date
    Oct 2012
    Posts
    42
    Thanks for the replies guys! I went with your suggestions and removed some stuff I didn't need and threw most of main() into functions.

    Code:
    #include <stdlib.h>
    #include <string.h>
    #include <stdio.h>
    
    // Creates the global linked list structure and defines linked list functions.
    struct node {
          int data;
          struct node *next;
    };
    typedef struct node link;
    link *searchList(int value, link *head);
    link *printList(link *current);
    link *populateList(link *current);
      
    int main() {
    
          // Initialize variables.
          struct node *head, *current, *temp;
          int search = 0;  
           
          // Initialize head node of linked list.
          head = calloc(1, sizeof(struct node));
          current = head;
          
          // Calls the list populate function and resets current node.
          populateList(current);
          current = head->next;
    
          // Calls the list print function.
          printList(current);
          
          // Prompts the user for a value and calls the list search function.
          printf("Enter a number to search for: ");
          scanf("%d", &search);
          current = head->next;
          printf("[%d %d]\n", search, searchList(search, head)->data);
          
          // Resets current node and frees all links from the list.
          current = head->next;
          while (current) {
                 temp = current->next;
                 free(current);
                 current = temp;
          }
          free(head);
          free(temp);
          return 0;
    }
      
    // Function to search list for matching number.
    link *searchList(int value, link *head) {
          struct node *temp;
          temp = head;
          while(head) {
                 if(value == head->data) {
                      return head;
             }
             head = head->next;
          }
          head = temp;
          free(temp);
          return head;
    }
    
    // Function to print all values in the linked list.
    link *printList(link *current) {
          printf("Printing linked list...\n");
          while (current) {
                 printf("%d\n", current->data);
                 current = current->next;
          }
    }
    
    // Function to populate linked list with values from 0-9.
    link *populateList(link *current) {
          struct node *temp;
          int i;
          for (i = 0; i <= 9; i++) {
                temp = calloc(1, sizeof(struct node));
                temp->data = i;
                current->next = temp;
                current = current->next;
          }
    }
    migf1, it is homework, so some of the code (like line 36, for example) I had to keep like it is.
    Also, why use puts() over printf()?

  6. #6
    Registered User migf1's Avatar
    Join Date
    May 2013
    Location
    Athens, Greece
    Posts
    385
    Quote Originally Posted by Paul Omans View Post
    ...
    Also, why use puts() over printf()?
    It is more of a nitpicking habit, there are no important differences if you only want to output a cstring. I find puts() less verbose, more convenient when a newline must be appended on the output, and in some implementations it executes faster (if my memory serves me well, most compilers optimize printf("whatverer\n") to puts("whatever") anyway).
    Last edited by migf1; 06-11-2013 at 10:20 AM.

  7. #7
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    Quote Originally Posted by migf1
    I find puts() less verbose, more convenient when a newline must be appended on the output, and in some implementations it executes faster (if my memory serves me well, most compilers optimize printf("whatverer\n") to puts("whatever") anyway).
    I find that "less verbose" and "more convenient" is really not much of a difference here. The key for me is that printf is intended for formatted output; puts is not. If you just intend to print a string and add a newline at the end, with no format specifiers, then puts describes your intention better than printf. Consequently, meeting your intention with the appropriate function may also lead to more optimal code, but that could well be just a bonus considering that I/O is relatively expensive to begin with.
    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

  8. #8
    Algorithm Dissector iMalc's Avatar
    Join Date
    Dec 2005
    Location
    New Zealand
    Posts
    6,318
    searchList is now very wrong. You're returning a pointer to something that has been freed, and you subsequently dereference it in main.
    searchList should not be calling free, and it does not need a temp variable either.
    My homepage
    Advice: Take only as directed - If symptoms persist, please see your debugger

    Linus Torvalds: "But it clearly is the only right way. The fact that everybody else does it some other way only means that they are wrong"

  9. #9
    Registered User
    Join Date
    May 2012
    Posts
    1,066
    Code:
    link *printList(link *current);
    link *populateList(link *current);
    Both functions don't return a link pointer.

    Code:
    link *searchList(int value, link *head) {
          struct node *temp;
          temp = head;
          while(head) {
                 if(value == head->data) {
                      return head;
             }
             head = head->next;
          }
          head = temp;
          free(temp);
          return head;
    }
    You destroy your list if the value isn't found.
    Why do you think you need to free "temp"?

    I've also noticed that you don't store data in the first node (the struct "head" points to). Why?

    Bye, Andreas

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. linked list search
    By RounakJain in forum C Programming
    Replies: 1
    Last Post: 05-07-2013, 10:07 PM
  2. Help on Linked List Search
    By sivapc in forum C++ Programming
    Replies: 8
    Last Post: 11-11-2009, 12:54 AM
  3. linked list search
    By rocketman03 in forum C Programming
    Replies: 5
    Last Post: 11-23-2008, 06:48 AM
  4. Replies: 12
    Last Post: 01-28-2006, 07:40 AM
  5. Linked list search??
    By ren in forum C Programming
    Replies: 2
    Last Post: 04-10-2002, 08:49 AM