Problem with Link List, This is written in C and not C++

MY APOLOGY IF YOU GUYS ARE EXPECTING A C++ PROGRAM. I AM JUST ASSUMING IF YOU KNOW C++ YOU MUST KNOW C. SO I AM TAKING A CHANCE THAT YOU WILL ANSWER MY QUESTION.

I have this file named "TestFile1" and it has this two lines.

1
2
The number-sign or "stringizing" operator (#) converts macro
parameters (after expansion) to string constants. It is used

and I have this header file name "List-Driver.h" that has this :
1
2
3
4
5
6
7
8
9
10
11
12
#ifndef LIST_DRIVER_H
#define LIST_DRIVER_H

/* Format of each list node... */
typedef struct List
{
   struct List *next;       
   char *str;           
   int count;           
} LIST;

#endif 


I have a main program "Main.c" having this code.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
#define INSTRUCTOR_FILE  
#ifdef INSTRUCTOR_FILE

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

#include "List-Driver.h"

#define FILENAME "TestFile1.txt"

FILE *OpenFile(const char *fileName);
LIST *CreateList(FILE *fp);
LIST *PrintList(const LIST *head);
void FreeList(LIST *head);

int main(void)
{
   FILE *fp = OpenFile(FILENAME);
   LIST *head = CreateList(fp);

   fclose(fp);
   FreeList(PrintList(head));

   return EXIT_SUCCESS;
}
#endif


And I have another .C file named "CreateList.c"
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include "List-Driver.h" 

#define LINE_LENGTH 128
#define INITIAL_VALUE 1

//Open the file that will be use to test the function CreateList
FILE *OpenFile(const char *fileName)
{
    FILE *FilePointer;
    if ((FilePointer = fopen(fileName, "r" )) == NULL)
    {
        fprintf(stderr, "Can't open \"filename\"\n");
        exit(EXIT_FAILURE);
    }
    return(FilePointer);
}

//This function will create a new LIST
LIST *CreateNewNode()
{
    LIST *NewNode;
    if ((NewNode =(LIST*) malloc( sizeof(LIST) )) == NULL)
    {
        fprintf(stderr, "Can't create Node \"pntr\"\n");
        exit(EXIT_FAILURE);
    }
    return(NewNode);
} 

LIST *CreateList(FILE *fp)
{
    //variable used on the linklist
    int createHeaderDone = 0, duplicateFound = 0, doneProcessingTheline = 0;
    LIST *headerList = NULL, *currentList = NULL, *traverserList = NULL;

    //Variable used on parsing the file
    char oneLine[LINE_LENGTH], *cutString, *delimiter = " ";       
    int leadingSpace; 

    while (fgets(oneLine, LINE_LENGTH, fp)) 
    { 
        //skip the leading white space 
        leadingSpace = 0;
        while (isspace(oneLine[leadingSpace++]))
            ;

        //this portion gets the section of a string up to but not including the  delimiter.
        //cutString = strtok(oneLine, delimiter); 
        //Create a header with one list element, this only happens once, only during the beginning when the file
        //is read for the first time.
        if (!createHeaderDone)
        {   
            headerList = NULL;          
            cutString = strtok(oneLine, delimiter); 
            currentList = CreateNewNode();
            currentList->next = headerList;
            headerList = currentList;
            headerList->str = cutString;
            headerList->count = INITIAL_VALUE;
            createHeaderDone = 1;
        }
        //this only happens once when reading the line 
        if (doneProcessingTheline) 
            {
                cutString = strtok(oneLine, delimiter); 
                currentList = CreateNewNode();
                currentList->next = headerList;
                headerList = currentList;
                currentList->count = INITIAL_VALUE;
                currentList->str = cutString; 
                doneProcessingTheline = 0;
            }
        while (cutString != NULL)
        {             
            cutString = strtok(NULL, delimiter);             
            currentList = CreateNewNode();
            currentList->next = headerList;
            headerList = currentList;
            headerList->count = INITIAL_VALUE;
            headerList->str = cutString; 
        }
        //Set the Flag indicating that the end of the line has been reached
        doneProcessingTheline = 1;
    }
    getchar();
    return(headerList);
}


When I start the program, I read the first line and create a link list by getting one word at a time and make a node. Then read the second word and link it at the begining of the LIST.
Everything is fine and dandy.

But when I read the second line, all the "str" of all the node suddenly changed.

What am I doing wrong? Why would a linklist change when I read the next line.
I am lost and confuse.

What am I doing wrong?


Setting the str member of each Node to point to a local buffer that goes out of scope when CreateList returns.

cire,

1. The way function "CreateList" works is it will open the file, process the file line by line, one line at a time and when the EOF is encountered that is the only time it exits the function. The way it is happening, I am still inside the function, the function just took the second line of the file and as soon as it grabs the second line all the headerList -> str, suddenly changed.

Anyway, assuming you are correct I declared *cutString to be static "static char *cutString", it did not work.

I declared "*headerList" to be global by declaring it outside the function, it did not work.

So what do you mean when you said " the str member of each Node to point to a local buffer that goes out of scope". I never left the function so all local variables are within the scope.
I never left the function so all local variables are within the scope.


Clearly you don't have a main function with code outside CreateList or the intention to use PrintList outside of CreateList. So those local variables will always be in scope, I'm sure.

If you would like, I'll rephrase:

Setting the str member of each Node to point to the same local buffer that goes out of scope when CreateList returns.
Last edited on
cire,

From the "main" I call "OpenFile", Get a file pointer and then call CreateList. My problem happens inside the function "CreateList". It is not that I left "CreateList and come back. I never left CreateList. From CreateList I get one line and create a LINKLIST when I reached the end of line I go to the outer while loop still inside function "CreateList " and get the next line. This is where I encounter the problem the -> str on all nodes will suddenly switch from a valid value to junk.

All 4 files are given on the initial topic and if you just cut and paste it will compile and run. And if you trace it you would see what I am talking about.
And if you listen to what I've said, you would be able to fix the problem.

I understand you have a problem in CreateList. You're going to have bigger problem outside of it.

mendozae wrote:
This is where I encounter the problem the -> str on all nodes will suddenly switch from a valid value to junk.


cire wrote:
Setting the str member of each Node to point to the same local buffer that goes out of scope when CreateList returns.


Maybe italics and bold will get the point across?

When you have pointers, and all the contents of the memory those pointers point to change at once.. do you think they might be pointing to the same place? And you keep reusing that memory? How many unique values can you store in one variable? And it's going to go out of scope when you leave the function?
The inherit problem is you're using a pointer to store a string, but the pointer points to a local variable that "changes".

The reason str member changes even inside the function is because it points to oneLine which changes on every loop.

For example,

TestFile1.txt
abc 123 def 456
car 321 fly 654

reading first line:
oneLine[] = "abc 123 def 456"

after parsing one line:
node1.str = "abc"
node2.str = "123"
node3.str = "def"
node4.str = "456"

reading second line:
oneLine[] = "car 321 fly 654"
now all the str members change because they all point to some index in oneLine
node1.str = "car"
node2.str = "321"
node3.str = "fly"
node4.str = "654"

To fix the problem, use static arrays or allocate memory dynamically.

ie.
char str[MAX_STRING];
strcpy(currentList->str, cutString); // copy the token
OR
currentList->str = new char[strlen(cutString)+1];
strcpy(currentList->str, cutString);
Cire,

My apology, stubborn me kept thinking that you are giving me recommendation without looking on the function.

Anyway, I did follow your advice and instead of assigning the same pointer to node->str, I have dynamic memory allocated to node->str and then memcpy ( node->str , cutString, sizeof memory) and it works.

Now that I know I can create a LinkList correctly I can proceed and do the actual assignment. This should be the easy part since it is the creation of the Listlist that is kicking my butt for 3 days.

I appreciate that you don't give me the answer directly and instead point me to the right direction.

Ed
Topic archived. No new replies allowed.