Thread: Read text file into a linked list

  1. #1
    Registered User
    Join Date
    Aug 2011
    Posts
    18

    Read text file into a linked list

    I'm having trouble dealing with the multiple lines of data in my text file:

    Fred Flintstone 38 Male
    Barney Rubble 36 Male
    Wilma Flintstone 37 Female
    Betty Rubble 36 Female
    Pebbles Flintstone 4 Female
    Bam-Bam Rubble 3 Male
    Dino Flintstone 2 Male
    Mr. Slate 57 Male
    Hoppy Rubble 1 Male
    Great Gazoo 11 Unknown
    Note: There are tabs, not spaces, before and after the numbers.

    I actually tried reading the data two ways, but both have been unsuccessful obviously. The first, my preferred method, does not involve an array of structures while the second one does. I'm thinking that using an array of structures maybe defeats the purpose of using linked lists. Just a guess. Still, I tried the second method anyway. I get no errors or warnings when I compile. I am using codeblocks as my compiler. Any tips on improving either one of my codes would be appreciated. Thank you.

    Method one (preferred):
    Code:
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <stdbool.h>
    
    #define LENGTH_OF_INPUT 35
    
    typedef int KEY_TYPE;
    typedef struct
    {
        char* name;
        KEY_TYPE age;
        char* gender;
    }DATA;
    
    typedef struct nodeTag
    {
        DATA character;
        struct nodeTag* link;
    }NODE;
    
    NODE* buildList (NODE* pList);
    bool getData (FILE* pData, DATA character);
    NODE* insertNode (NODE*pList, NODE* pPre, DATA character);
    void printList (NODE* pList);
    
    int main(void)
    {
        NODE* pList;
    
        pList = NULL;
    
        pList = buildList (pList);
    
        printList (pList);
    
        return 0;
    }
    
    NODE* buildList (NODE* pList)
    {
        FILE* pData;
        NODE* pPre;
        DATA character;
    
        pPre = NULL;
    
        if ((pData = fopen("lab6data.txt", "r"))==NULL)
        {
            printf("Error opening text file.\n");
            exit (100);
        }
    
        while (getData(pData, character));
        {
            pList = insertNode (pList, pPre, character);
        }
    
        if (fclose(pData) == EOF )
    	{
    	printf("Error closing lab6data.txt\n");
    	exit (300);
    	}
    
        return pList;
    }
    
    bool getData (FILE* pData, DATA character)
    {
        char input [LENGTH_OF_INPUT];
        char name [LENGTH_OF_INPUT];
        char gender [LENGTH_OF_INPUT];
    
    
        if (!feof(pData))
        {
            while (fgets(input, 34, pData))
            {
                sscanf(input, "%19[^\t]%d %[^\n]", name, &character.age, gender);
    
                character.name = calloc(strlen(name) + 1, sizeof(char));
                strcpy(character.name, name);
    
                character.gender = calloc(strlen(gender) + 1, sizeof(char));
                strcpy(character.gender, gender);
            }
            return true;
        }
    
        else
        {
            return false;
        }
    
    }
    
    NODE* insertNode (NODE*pList, NODE* pPre, DATA character)
    {
        NODE* pNew;
    
        if (!(pNew = (NODE*)malloc(sizeof(NODE))))
        {
            printf("Memory overflow in insert\n");
            exit(200);
        }
    
        pNew->character = character;
    
        pNew->link = NULL;
        if (pPre == NULL)
        {
            pNew->link = NULL;
    
            if (pList == NULL)
            {
                pList = pPre = pNew;
            }
            else
            {
                pPre->link = pNew;
                pPre = pNew;
            }
        }
    
        return pList;
    }
    
    void printList (NODE* pList)
    {
        NODE* pWalker;
    
        pWalker = pList;
        printf ("\nList contains:\n");
    
        while (pWalker)
        {
            printf ("%s %d %s\n", pWalker->character.name, pWalker->character.age, pWalker->character.gender);
            pWalker = pWalker->link;
        }
        printf ("<End of List>\n\n");
        return;
    }
    Method 2:
    Code:
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    
    #define LENGTH_0F_ARRAY 10
    #define LENGTH_OF_INPUT 35
    
    typedef int KEY_TYPE;
    typedef struct
    {
        char* name;
        KEY_TYPE age;
        char* gender;
    }DATA;
    
    typedef struct nodeTag
    {
        DATA character;
        struct nodeTag* link;
    }NODE;
    
    NODE* buildList (NODE* pList);
    void getData (DATA* pChar);
    NODE* insertNodes(NODE* pList, NODE* pPre, NODE* pCur, DATA* pChar);
    void printList (NODE* pList);
    
    int main(void)
    {
        NODE* pList;
    
        pList = NULL;
    
        pList = buildList (pList);
    
        printList (pList);
    
        return 0;
    }
    
    NODE* buildList (NODE* pList)
    {
        DATA* pChar;
        NODE* pPre;
        NODE* pCur;
    
        pPre = NULL;
        pCur = NULL;
        pChar = calloc(LENGTH_0F_ARRAY, sizeof(DATA));
    
        getData(pChar);
    
        pList = insertNodes(pList, pPre, pCur, pChar);
    
        return pList;
    }
    
    void getData (DATA* pChar)
    {
        FILE* pData;
        int charIndex;
        char input [LENGTH_OF_INPUT];
        char name [LENGTH_OF_INPUT];
        char gender [LENGTH_OF_INPUT];
    
        if ((pData = fopen("lab6data.txt", "r"))==NULL)
        {
            printf("Error opening text file.\n");
            exit (100);
        }
    
        charIndex = 0;
        while (charIndex<LENGTH_0F_ARRAY && fgets(input, 34, pData))
        {
            sscanf(input, "%19[^\t]%d %[^\n]", name, &pChar[charIndex].age, gender);
    
            pChar[charIndex].name = calloc(strlen(name) + 1, sizeof(char));
            strcpy(pChar[charIndex].name, name);
    
            pChar[charIndex].gender = calloc(strlen(gender) + 1, sizeof(char));
            strcpy(pChar[charIndex].gender, gender);
    
            charIndex++;
        }
    
        if (fclose(pData) == EOF )
    	{
    	printf("Error closing lab6data.txt\n");
    	exit (200);
    	}
    
    	return;
    
    }
    
    NODE* insertNodes(NODE* pList, NODE* pPre, NODE* pCur, DATA* pChar)
    {
        int charIndex;
        NODE* pNew;
    
        if (!(pNew = (NODE*)malloc(sizeof(NODE))))
        {
            printf("Memory overflow in insert\n"),
            exit(300);
        }
    
        for (charIndex = 0; charIndex < LENGTH_0F_ARRAY; charIndex++)
        {
            pNew->character = pChar[charIndex];
            pNew->link = NULL;
    
            if (pList == NULL)
            {
                pList = pPre = pNew;
            }
            else
            {
                pPre->link = pNew;
                pPre = pNew;
            }
        }
    
        return pList;
    
    }
    
    void printList (NODE* pList)
    {
        NODE* pWalker;
    
        pWalker = pList;
        printf ("\nList contains:\n");
    
        while (pWalker)
        {
            printf ("%s %d %s\n", pWalker->character.name, pWalker->character.age, pWalker->character.gender);
            pWalker = pWalker->link;
        }
        printf ("<End of List>\n\n");
        return;
    }
    Last edited by riddinon24z; 08-02-2011 at 08:47 PM.

  2. #2
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    Quote Originally Posted by riddinon24z
    I actually tried reading the data two ways, but both have been unsuccessful obviously.
    That is not obvious

    Let's concentrate on your first method, since it involves what you are actually trying to do. How does it not work?

    Quote Originally Posted by riddinon24z
    I'm thinking that using an array of structures maybe defeats the purpose of using linked lists.
    Yes, unless you need such an array for some other purpose.
    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

  3. #3
    Registered User
    Join Date
    Oct 2008
    Location
    TX
    Posts
    2,059
    The DATA members name/gender need storage set aside for holding data items and can't just point to them.
    Use array of structures when the number of records in the input file is known beforehand, else use linked lists.

  4. #4
    Registered User
    Join Date
    Aug 2011
    Posts
    18
    I think I see what you're saying. So I should put something like this in my insertNode function:
    pNew->character.name = calloc(strlen(character.name) + 1, sizeof(char));
    pNew->character.gender = calloc(strlen(character.gender) + 1, sizeof(char));
    The reason I'm using dynamic memory allocation is because my teacher told us to do so.

  5. #5
    Registered User
    Join Date
    Aug 2011
    Posts
    18
    I'm just thinking out loud. What I'm trying to do is read one line of data from the text file into a node. Then insert that node into my list and put that entire process into a loop until all lines are read. Do I have the right idea, looking at my code from method 1?

  6. #6
    Registered User
    Join Date
    May 2011
    Location
    Around 8.3 light-minutes from the Sun
    Posts
    1,949
    Quote Originally Posted by riddinon24z View Post
    I'm just thinking out loud. What I'm trying to do is read one line of data from the text file into a node. Then insert that node into my list and put that entire process into a loop until all lines are read.
    Yes, that is the right idea. Now implement it and if it doesn't work tell us what doesn't work and provide the appropriate code segment that isn't working.
    Quote Originally Posted by anduril462 View Post
    Now, please, for the love of all things good and holy, think about what you're doing! Don't just run around willy-nilly, coding like a drunk two-year-old....
    Quote Originally Posted by quzah View Post
    ..... Just don't be surprised when I say you aren't using standard C anymore, and as such,are off in your own little universe that I will completely disregard.
    Warning: Some or all of my posted code may be non-standard and as such should not be used and in no case looked at.

  7. #7
    Banned
    Join Date
    Aug 2010
    Location
    Ontario Canada
    Posts
    9,547
    Quote Originally Posted by riddinon24z View Post
    I'm just thinking out loud. What I'm trying to do is read one line of data from the text file into a node. Then insert that node into my list and put that entire process into a loop until all lines are read. Do I have the right idea, looking at my code from method 1?
    You have the right idea... make it so!

  8. #8
    Registered User
    Join Date
    May 2011
    Location
    Around 8.3 light-minutes from the Sun
    Posts
    1,949
    Quote Originally Posted by CommonTater View Post
    You have the right idea... make it so!

    LOL.......
    Quote Originally Posted by anduril462 View Post
    Now, please, for the love of all things good and holy, think about what you're doing! Don't just run around willy-nilly, coding like a drunk two-year-old....
    Quote Originally Posted by quzah View Post
    ..... Just don't be surprised when I say you aren't using standard C anymore, and as such,are off in your own little universe that I will completely disregard.
    Warning: Some or all of my posted code may be non-standard and as such should not be used and in no case looked at.

  9. #9
    Registered User
    Join Date
    Aug 2011
    Posts
    18
    Ok. Here's what I came up with. I changed the type of the getData function from bool to void. Don't know whether or not that was a good idea. I took the fgets function from getData and put it into the while loop of the buildList function. I also put a printf statement to print each line of data each time the getData function runs. Sorry if I worded that incorrectly. When I execute, the print statement prints the last line in the text data. I don't understand why it doesn't start with the first line and just jumps to the last. As for my linked list output, it's just "garbage" basically. Right now I'm just worrying about reading the first line of data into a node. I also allocated the memory for the data in each incoming node. I'm not getting any errors or warnings. I don't really have a question. I don't know what to think.

    Code:
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    
    #define LENGTH_OF_INPUT 35
    
    typedef int KEY_TYPE;
    typedef struct
    {
        char* name;
        KEY_TYPE age;
        char* gender;
    }DATA;
    
    typedef struct nodeTag
    {
        DATA character;
        struct nodeTag* link;
    }NODE;
    
    NODE* buildList (NODE* pList);
    void getData (FILE* pData, DATA line, char input []);
    NODE* insertNode (NODE*pList, NODE* pPre, DATA line);
    void printList (NODE* pList);
    
    int main(void)
    {
        NODE* pList;
    
        pList = NULL;
    
        pList = buildList (pList);
    
        printList (pList);
    
        return 0;
    }
    
    NODE* buildList (NODE* pList)
    {
        char input [LENGTH_OF_INPUT];
        FILE* pData;
        NODE* pPre;
        DATA line;
    
        pPre = NULL;
    
        if ((pData = fopen("lab6data.txt", "r"))==NULL)
        {
            printf("Error opening text file.\n");
            exit (100);
        }
    
        while (fgets(input, 34, pData));
        {
            getData(pData, line, input);
            pList = insertNode (pList, pPre, line);
        }
    
        if (fclose(pData) == EOF )
    	{
    	printf("Error closing lab6data.txt\n");
    	exit (300);
    	}
    
        return pList;
    }
    
    void getData (FILE* pData, DATA line, char input [])
    {
        char name [LENGTH_OF_INPUT];
        char gender [LENGTH_OF_INPUT];
    
        sscanf(input, "%19[^\t]%d %[^\n]", name, &line.age, gender);
    
        line.name = calloc(strlen(name) + 1, sizeof(char));
        strcpy(line.name, name);
    
        line.gender = calloc(strlen(gender) + 1, sizeof(char));
        strcpy(line.gender, gender);
    
        printf("%s %d %s", line.name, line.age, line.gender);
    
    
        return;
    }
    
    NODE* insertNode (NODE*pList, NODE* pPre, DATA line)
    {
        NODE* pNew;
    
        if (!(pNew = (NODE*)malloc(sizeof(NODE))))
        {
            printf("Memory overflow in insert\n");
            exit(200);
        }
    
        pNew->character.name = calloc(strlen(line.name) + 1, sizeof(char));
        pNew->character.gender = calloc(strlen(line.gender) + 1, sizeof(char));
    
        pNew->character = line;
        pNew->link = NULL;
    
        if (pPre == NULL)
        {
            pNew->link = NULL;
    
            if (pList == NULL)
            {
                pList = pPre = pNew;
            }
            else
            {
                pPre->link = pNew;
                pPre = pNew;
            }
        }
    
        return pList;
    }
    
    void printList (NODE* pList)
    {
        NODE* pWalker;
    
        pWalker = pList;
        printf ("\nList contains:\n");
    
        while (pWalker)
        {
            printf ("%s %d %s\n", pWalker->character.name, pWalker->character.age, pWalker->character.gender);
            pWalker = pWalker->link;
        }
        printf ("<End of List>\n\n");
        return;
    }
    Last edited by riddinon24z; 08-02-2011 at 09:57 PM.

  10. #10
    and the Hat of Guessing tabstop's Avatar
    Join Date
    Nov 2007
    Posts
    14,336
    You should probably make your insertNode function insert a node; right now it's just losing a lot of data, since a function is unable to change the values of any of its input parameters (so pPre cannot change). If you want to change the value of pPre, you must give your function the address of pPre, so that it can replace the value in memory.

  11. #11
    Banned
    Join Date
    Aug 2010
    Location
    Ontario Canada
    Posts
    9,547
    The only thing I'd change is the struct itself...

    Code:
    typedef struct
    {
        char* name;
        KEY_TYPE age;
        char* gender;
    }DATA;
    
    typedef struct nodeTag
    {
        DATA character;
        struct nodeTag* link;
    }NODE;
    First these do not need to be two separate structs... combine them and save yourself some headaches.
    Second I would put the actual data storage in the resulting single struct... That way when you malloc() your struct, you also create your string space and free() will remove it automatically in a single step.

    Like this...
    Code:
    typedef struct t_NODE
    {
        char name[20];
        int age;
        char gender;
        DATA character;
        struct t_NODE *next;
    } NODE;
    Gender can be simply M, F or T ... Don't forget transgendered people!

    Now when you malloc(sizeof(NODE)) you've also created your string space for the name as well.

  12. #12
    Registered User
    Join Date
    Aug 2011
    Posts
    18
    Quote Originally Posted by tabstop View Post
    You should probably make your insertNode function insert a node; right now it's just losing a lot of data, since a function is unable to change the values of any of its input parameters (so pPre cannot change). If you want to change the value of pPre, you must give your function the address of pPre, so that it can replace the value in memory.
    Oh I guess I kinda forgot c programming 101. So that means my getData function will also be affected by your advice. I changed the type of the getData function again but this time to my structure type DATA. I came up with this:
    Code:
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    
    #define LENGTH_OF_INPUT 35
    
    typedef int KEY_TYPE;
    typedef struct
    {
        char* name;
        KEY_TYPE age;
        char* gender;
    }DATA;
    
    typedef struct nodeTag
    {
        DATA character;
        struct nodeTag* link;
    }NODE;
    
    NODE* buildList (NODE* pList);
    DATA getData (FILE* pData, DATA line, char input []);
    NODE* insertNode (NODE* pList, NODE** pPre, DATA line);
    void printList (NODE* pList);
    
    int main(void)
    {
        NODE* pList;
    
        pList = NULL;
    
        pList = buildList (pList);
    
        printList (pList);
    
        return 0;
    }
    
    NODE* buildList (NODE* pList)
    {
        char input [LENGTH_OF_INPUT];
        FILE* pData;
        NODE* pPre;
        DATA line;
    
        pPre = NULL;
    
        if ((pData = fopen("lab6data.txt", "r"))==NULL)
        {
            printf("Error opening text file.\n");
            exit (100);
        }
    
        while (fgets(input, 34, pData));
        {
            line = getData(pData, line, input);
            printf("%s %d %s", line.name, line.age, line.gender);
            pList = insertNode (pList, &pPre, line);
        }
    
        if (fclose(pData) == EOF )
    	{
    	printf("Error closing lab6data.txt\n");
    	exit (300);
    	}
    
        return pList;
    }
    
    DATA getData (FILE* pData, DATA line, char input [])
    {
        char name [LENGTH_OF_INPUT];
        char gender [LENGTH_OF_INPUT];
    
        sscanf(input, "%19[^\t]%d %[^\n]", name, &line.age, gender);
    
        line.name = calloc(strlen(name) + 1, sizeof(char));
        strcpy(line.name, name);
    
        line.gender = calloc(strlen(gender) + 1, sizeof(char));
        strcpy(line.gender, gender);
    
        return line;
    }
    
    NODE* insertNode (NODE* pList, NODE** pPre, DATA line)
    {
        NODE* pNew;
    
        if (!(pNew = (NODE*)malloc(sizeof(NODE))))
        {
            printf("Memory overflow in insert\n");
            exit(200);
        }
    
        pNew->character.name = calloc(strlen(line.name) + 1, sizeof(char));
        pNew->character.gender = calloc(strlen(line.gender) + 1, sizeof(char));
    
        pNew->character = line;
        pNew->link = NULL;
    
        if ((*pPre) == NULL)
        {
            pNew->link = NULL;
    
            if (pList == NULL)
            {
                pList = (*pPre) = pNew;
            }
            else
            {
                (*pPre)->link = pNew;
                (*pPre) = pNew;
            }
        }
    
        return pList;
    }
    
    void printList (NODE* pList)
    {
        NODE* pWalker;
    
        pWalker = pList;
        printf ("\nList contains:\n");
    
        while (pWalker)
        {
            printf ("%s %d %s\n", pWalker->character.name, pWalker->character.age, pWalker->character.gender);
            pWalker = pWalker->link;
        }
        printf ("<End of List>\n\n");
        return;
    }
    My output is this
    Great Gazoo 11 Unknown
    List contains:
    Great Gazoo 11 Unknown
    <End of List>


    Process returned 0 (0x0) execution time : 0.139 s
    Press any key to continue.
    Why does it just jump to the last line?

  13. #13
    Lurking whiteflags's Avatar
    Join Date
    Apr 2006
    Location
    United States
    Posts
    9,612
    I don't think that you're exactly following tabstop's advice. We could make things a whole lot simpler just by allocating nodes in ONE function.

    For a list with a null tail, do this (with item being where to insert, list being the list, and n being a node):
    Code:
     Insert n after item:
       if ( item == NULL ) {
         list = n;
         list->next = NULL;
       }
       else {
         n->next = item->next;
         item->next = n;
       }
    Then you return the list pointer.

    Which I lifted from Cprogramming.com FAQ > Linked List Issues.

    Why does it just jump to the last line?
    I wager this is not what is happening and you are merely failing to link your list correctly.

  14. #14
    Registered User
    Join Date
    Aug 2011
    Posts
    18
    Quote Originally Posted by riddinon24z View Post
    I'm just thinking out loud. What I'm trying to do is read one line of data from the text file into a node. Then insert that node into my list and put that entire process into a loop until all lines are read. Do I have the right idea, looking at my code from method 1?
    If instead I tried to insert the nodes in numerical order based on the age, which would be new->.character.age, is it illogical or incorrect for me to have my if statement the opposite of my while loop statement for checking the values?

    Code:
    NODE* getDataAndInsert (FILE* pData)
    {
        NODE* pList;
        DATA line;
        char input [LENGTH_OF_INPUT];
        char name [LENGTH_OF_INPUT];
        char gender [LENGTH_OF_INPUT];
    
        pList = NULL;
    
        while (fgets(input, 34, pData))
        {
            sscanf(input, "%19[^\t]%d %[^\n]", name, &line.age, gender);
    
            line.name = calloc(strlen(name) + 1, sizeof(char));
            strcpy(line.name, name);
    
            line.gender = calloc(strlen(gender) + 1, sizeof(char));
            strcpy(line.gender, gender);
    
            pList = insertNode (pList, line);
        }
    
        return pList;
    }
    
    NODE* insertNode (NODE* pList, DATA line)
    {
        NODE* pNew;
        NODE* pPre;
        NODE* pCur;
    
        if (!(pNew = (NODE*)malloc(sizeof(NODE))))
        {
            printf("Memory overflow in insert\n");
            exit(200);
        }
    
        pNew->character.name = calloc(strlen(line.name) + 1, sizeof(char));
        pNew->character.gender = calloc(strlen(line.gender) + 1, sizeof(char));
        pNew->character = line;
    
        pPre = NULL;
        pCur = pList;
    
    	printf("%d\n", pNew->character.age);
    
        while ((pNew->character.age < pPre->character.age) && (pCur->link != NULL))
        {
            traverse (&pPre, &pCur);
        }
    
        if (pNew->character.age >= pPre->character.age)
        {
            pNew->link = pPre->link;
            pPre->link = pNew;
        }
    
        else if (pCur == NULL)
        {
            pNew->link = NULL;
            pList = pNew;
        }
    
        return pList;
    }
    
    void traverse (NODE** pPre, NODE** pCur)
    {
        *pPre = (*pCur);
        *pCur = (*pCur)->link;
    
        return;
    }
    Last edited by riddinon24z; 08-03-2011 at 07:54 PM.

  15. #15
    Registered User
    Join Date
    Aug 2011
    Posts
    18
    I changed a portion of the insertNode function. Am I not accounting for every situation?
    Code:
    pPre = NULL;
    pCur = pList;
    
    while ((pNew->character.age < pPre->character.age) && (pCur->link != NULL))
        {
            traverse (&pPre, &pCur);
        }
    
        if (pNew->character.age >= pPre->character.age)
        {
            pNew->link = pPre->link;
            pPre->link = pNew;
        }
    
        else if (pCur->link == NULL)
        {
            pNew->link = pCur->link;
            pPre->link = pNew;
        }
    
        else if (pList == NULL)
        {
            pNew->link = NULL;
            pList = pNew;
        }
    
        else
        {
            ;
        }
    
        return pList;
    Last edited by riddinon24z; 08-03-2011 at 07:54 PM.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Reading Text file in Linked list!
    By satty in forum C Programming
    Replies: 20
    Last Post: 07-29-2010, 08:48 AM
  2. read a text file and display the content into the list box
    By mr_empty in forum Windows Programming
    Replies: 10
    Last Post: 12-18-2007, 12:55 AM
  3. Replies: 5
    Last Post: 08-01-2007, 06:17 AM
  4. read file into Linked list, please
    By unhwan in forum C Programming
    Replies: 3
    Last Post: 06-11-2002, 07:18 PM
  5. How to read a file to a linked list?
    By c beginner in forum C Programming
    Replies: 1
    Last Post: 04-09-2002, 10:59 AM