warnings and segmentation fault

I wrote a program that gets the name of a file from a argument vector then it reads info from that file into a linked structure list, then it either searches for name, social security number or prints all the structures. I am getting some warnings and when I run the program i get a segmentation fault. here is my 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
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
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
 # include <iostream>
# include <cstring>
# include <fstream>
# include <cctype>
# include <cstdlib>
# include <cstdio>

// structure definition
struct student
{
        char firstName[21];     // first name of student
        char middleIn;      // middle initial of student
        char lastName[21];      // last name of student
        char SSN[10];      // social security number of student
        struct student * next;     // pointer to link structures
};

// function prototypes
int readFile( struct student *, char *, int );   // opens input file and reads info into structures
void searchName( struct student * );            // searchs through structures and prints out records that have last
                                               // name entered by user
void searchNum( struct student * );           // searchs through structures for a record that has a SSN number that
                                             // the user has entered
void printList( struct student *, int );         // prints entire list of student structures
void destroyList( struct student * );      // destroys space when program quits

using namespace std;

int main( int argc, char * argv [] )
{
        char fileName[20];      // name of file
        struct student * record;     // structure of strudent info
        int numStudents;      // number of student structures created from input file
        int choice;      // option chosen by user

        // see if filename is in argv
        if( argc == 0 )
        {
                cerr << "No file name included\n";
                exit( EXIT_FAILURE );      // end program after printing error
        }
        else
                //call function to read from file
                strcpy( fileName, argv[1] );
                readFile( record, fileName, numStudents );

        // print user interface
        cout << "1. Search for a Student by Last Name\n";
        cout << "2. Search for a Student by SSN number\n";
        cout << "3. Print full list of Students\n";
        cout << "4. Quit\n";
        cin >> choice;

        while( choice != 4 )
        {
                if( choice == 1 )
                {
                        searchName( record );
                }
                else if( choice == 2 )
                {
                        searchNum( record );
                }
                else if( choice == 3 )
                {
                        printList( record, numStudents );
                }
                else
                        cerr << "Invalid Choice\n";
                        exit( EXIT_FAILURE );

                // pause program
                cout << "Press ENTER to continue";
                cin.get ( );
                cin.ignore ( 1, '\n' );
        }
        destroyList( record );

        return 0;
}

int readFile( struct student * start, char fileName[], int numStudents )
{
        ifstream input;     // input stream used
        struct student * current;    // where parser is located
        struct student * newrecord;     // pointers for future use
        char buffer[81];     // string that is read from file
        int count;     // count for loop
        int length;    // length of line read from file

        // open input file
        input.open( fileName );
        if( !input.is_open() )
        {
                cerr << "Unable to open input file:" << fileName << "\n";
                exit( 1 );
        }

        numStudents= 0;
        start = NULL;
        // do a priming read
        input.getline( buffer, 81 );
        while( !input.eof() )
        {
                length = strlen( buffer );
                for( count = 0; count < length; count++ )
                {
                        if( strncasecmp( buffer, "<STUDENT>", length ) )
                        {
                                newrecord = new struct student;
                                if( newrecord )
                                {
                                        newrecord -> next = NULL;
                                }
                        }
                        else if( strncasecmp( buffer, "<FIRST>", length ) )
                        {
                                input.getline( buffer, 81 );
                                while( length  == 0 )
                                {
                                        input.getline( buffer, 81 );
                                }
                                strcpy( newrecord -> firstName, buffer );
                        }
                        else if( strncasecmp( buffer, "<MI>", length ) )
                        {
                                input.getline( buffer, 81 );
                                while( length  == 0 )
                                {
                                        input.getline( buffer, 81 );
                                }
                                newrecord -> middleIn = * buffer;
                        }
                        else if( strncasecmp( buffer, "<LAST>", length ) )
                        {
                                input.getline( buffer, 81 );
                                while( length  == 0 )
                                {
                                        input.getline( buffer, 81 );
                                }
                                strcpy( newrecord -> lastName, buffer );
                        }
                        else if( strncasecmp( buffer, "<SSN>", length ) )
                        {
                                input.getline( buffer, 81 );
                                while( length == 0 )
                                {
                                        input.getline( buffer, 81 );
                                }
                                strcpy( newrecord -> SSN, buffer );
                        }
                        else if( strncasecmp( buffer, "</STUDENT>", length ) )
                        {
                                numStudents++;
                                if( start == NULL )
                                {
                                        start = current = newrecord;
                                }
                                else
                                        current -> next = newrecord;
                                        current = current -> next;
                        }
                        input.getline( buffer, 81 );
                }
        }
        input.close();

        return numStudents;
}

Last edited on
functions of program
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
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
/* searchName: searchs through structures and prints structure that has last name entered by user
 * Parameters:
 *      start: start of linked list
 * Returns nothing
*/
void searchName( struct student * start )
{
        char last[20];      // last name entered by user
        int count;      // count for loop
        int results;    // total records found with last name

        // prompt user for last name
        cout << "Please enter the last name of a student\n";
        cin >> last;

        // loop to parse through linked list and find structure with last name
        while( start != NULL )
        {
                if( strncasecmp( last, start -> lastName, 21 ) == 0 )
                {
                        cout << "A student with that last name: \n";
                        for( count = 0; count < 10; count++ )
                        {
                                if( count <= 3 )
                                {
                                        cout << start -> SSN[count] << "-";
                                }
                                else if( count <= 5 )
                                {
                                        cout << start -> SSN[count] << "-";
                                }
                                else
                                        cout << start -> SSN[count] << "\n";
                        }
                        for( count = 0; count < 21; count ++ )
                        {
                                if( count == 1 )
                                {
                                        cout << toupper( start -> firstName[count] );
                                }
                                else
                                        cout << tolower( start ->  firstName[count] ) << " ";
                        }
                        cout << toupper( start -> middleIn ) << " ";
                        for( count = 0; count < 21; count ++ )
                        {
                                if( count == 1 )
                                {
                                        cout << toupper( start -> lastName[count] ) << "\n";
                                }
                                else
                                        cout << tolower( start -> lastName[count] ) << "\n";
                        }
                        results++;
                }
                start = start -> next;
        }

        // check to see if any results found
        if( results == 0 )
        {
                cout << "Nobody present with that last name\n";
        }
}

/* searchNum: searches through structures and prints the one that has number entered by user
 * Parameters:
 *      start: start of linked list
 * Returns: nothing
*/
void searchNum( struct student * start )
{
        int count;    // count for loop
        char social[10];   // SSN entered by user
        int results;    // number of results found

        // prompt user for SSN
        cout << "Please enter a Social Security number\n";
        cin >> social;

        // loop to parse through structures and find structure with SSN
        while( start != NULL )
        {
                if( strcmp( social, start -> SSN ) == 0 )
                {
                        cout << "A student with that Social Security Number: \n";
                        for( count = 0; count < 10; count++ )
                        {
                                if( count <= 3 )
                                {
                                        cout << start -> SSN[count] << "-";
                                }
                                else if( count <= 5 )
                                {
                                        cout << start -> SSN[count] << "-";
                                }
                                else
                                        cout << start -> SSN[count] << "\n";
                        }
                        for( count = 0; count < 21; count ++ )
                        {
                                if( count == 1 )
                                {
                                        cout << toupper( start -> firstName[count] );
                                }
                                else
                                        cout << tolower( start -> firstName[count] ) << " ";
                        }
                        cout << toupper( start -> middleIn ) << " ";
                        for( count = 0; count < 21; count ++ )
                        {
                                if( count == 1 )
                                {
                                        cout << toupper( start -> lastName[count] ) << "\n";
                                }
                                else
                                        cout << tolower( start -> lastName[count] ) << "\n";
                        }
                        results++;
                }
                start = start -> next;
        }
         // check to see if any results found
        if( results == 0 )
        {
                cout << "Nobody present with that SSN\n";
        }
}

/* printList: prints total student structures that are stored
 * Parameters:
 *      start: start of linked list
 *      numRecords: number of structures
 * Returns nothing
*/
void printList( struct student * start, int numRecords )
{
        int count;     // count for loop

        // loop to parse through structures to print records
        while( start != NULL )
        {
                cout << "Total records processed: " << numRecords << "\n";
                for( count = 0; count < 10; count++ )
                {
                        if( count <= 3 )
                        {
                                cout << start -> SSN[count] << "-";
                        }
                        else if( count <= 5 )
                        {
                                cout << start -> SSN[count] << "-";
                        }
                        else
                                cout << start -> SSN[count] << "\n";
                }
                for( count = 0; count < 21; count ++ )
                {
                        if( count == 1 )
                        {
                                cout << toupper( start -> firstName[count] );
                        }
                        else
                                cout << tolower( start -> firstName[count] ) << " ";
                }
                cout << toupper( start -> middleIn ) << " ";
                for( count = 0; count < 21; count ++ )
                {
                        if( count == 1 )
                        {
                               cout << toupper( start -> lastName[count] ) << "\n";
                        }
                        else
                               cout << tolower( start -> lastName[count] ) << "\n";
                }
        }
        start = start -> next;
}

/* destroyList: destroys space dynamically created
 * Parameters:
 *      start: start of linked list
 * Returns nothing
*/
void destroyList( struct student * start )
{
        student * temp;     // hold current address while moving

        // traverse through with loop and delete storage
        while( start != NULL )
        {
                temp = start;
                start = start -> next;
                delete temp;
        }
}
 


and these are the warnings
1
2
3
main.cpp: In function 'int main(int, char**)':
main.cpp:28: warning: 'record' may be used uninitialized in this function
main.cpp:28: warning: 'numStudents' may be used uninitialized in this function


any ideas on how I can fix this?
You didn't post what the warnings were as you should've. I'm guessing one of the warnings was that record is uninitialized when it is first used on line 45 in readFile. As readFile is incapable of modifying record, it still contains some random value when is used on lines 58, 62, 66 and 77. That's a lot of potential undefined behavior.
try these changes:

line 19:
int readFile( struct student *, char *, int *);

line 32:
struct student * record = NULL; // structure of strudent info

line 33:
int numStudents = 0; // number of student structures created from input file

line 45:
readFile( record, fileName, &numStudents );

line 82:
int readFile( struct student * start, char fileName[], int *numStudents )

line 168:
return *numStudents;



That takes care of the warnings... the line causing the segfault is here:
strcpy( fileName, argv[1] );

I suggest you add a line printing argc before this line is run and see if argc behaves as you'd expect... I bet it doesn't.
Last edited on
That takes care of the warnings... the line causing the segfault is here:
strcpy( fileName, argv[1] );

That may take care of the warnings, but the code is not correct and that is not the source of the segfault. As I may have mentioned before, readFile is not capable of modifying the student* that is fed to it. Changes to start in readFile will be lost when the function returns.

Subsequent calls to functions expecting record to contain the address of a valid student will dereference the random address that is actually contained by record causing undefined behavior (and likely resulting in said segfault.)

It is quite possible there are other issues in the code, but this is the one that needs to be tackled most urgently.
cire: The line causing the **first** segfault is the one I identified... I expect that there will be other issues, but that one needs tackled first.

Can you give a good explanation as to why modifying the contents of a passed pointer will not work and perhaps how miamidawgs could correct his code to behave as he would expect it to?
ValliusDax wrote:
cire: The line causing the **first** segfault is the one I identified... I expect that there will be other issues, but that one needs tackled first.


1
2
3
4
5
6
7
        char fileName[20];
        // ...

        if( argc == 0 )
                // ...
        else
                strcpy( fileName, argv[1] );


Unless argv[1] happens to contain a string that is greater than 19 characters in length, this is perfectly well defined. It would be nice, of course, if the OP just used argv[1] in the next function call and got rid of fileName altogether which would make a buffer overrun there completely impossible. But, perhaps you can explain how there is an absolute certainty that a segfault happens here?


ValliusDax wrote:
Can you give a good explanation as to why modifying the contents of a passed pointer will not work and perhaps how miamidawgs could correct his code to behave as he would expect it to?

Modifying the contents of a passed pointer will work just fine. The problem is that, by default, arguments are passed by value, which means that the function receives a copy of the pointer that exists in main. Modifications to the copy in the function have no effect on the original. Passing the pointer by reference would solve that particular problem.

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
#include <iostream>

void modify_pointer_byvalue(const char* p)
{
    p = "by value";
}

void modify_pointer_byreference(const char*& p)
{
    p = "by reference";
}

void modify_pointer_byindirection(const char** p)
{
    *p = "by indirection";
}

int main()
{
    const char* ptr = "original";
    std::cout << "Before modification: \"" << ptr << "\"\n";

    modify_pointer_byvalue(ptr);
    std::cout << "After value: \"" << ptr << "\"\n";

    modify_pointer_byreference(ptr);
    std::cout << "After reference: \"" << ptr << "\"\n";

    modify_pointer_byindirection(&ptr);
    std::cout << "After indirection: \"" << ptr << "\"\n";
}


http://ideone.com/zJ6Bd7
Unless argv[1] happens to contain a string that is greater than 19 characters in length, this is perfectly well defined. It would be nice, of course, if the OP just used argv[1] in the next function call and got rid of fileName altogether which would make a buffer overrun there completely impossible. But, perhaps you can explain how there is an absolute certainty that a segfault happens here?


Compile the code and run it without arguments... segfault on accessing a non-existent argv[1]. As I said, argc doesn't behave like the OP thinks it does, it will almost always be 1 or greater as argv[0] is normally the command used to call the executable itself (I say almost always as I have heard tales of this not being the case on some systems, but have never encountered it myself).

Basically the OP's if(argc==0) will never execute, if(argc<=1) is a safer way to do this, and will prevent the first segfault.

Thanks for the explanation... I hadn't thought of that... this isn't how I normally use pointers so it didn't occur to me right away.

I can now see how allocating a pointer (using new or malloc()) would fail, but if the structure being pointed to were allocated in main and modified in the function, would that also fail?
You're absolutely right about argc. Sometimes you can look right at a thing and just not see it until someone hits you over the head with it. Thanks for hitting me over the head. =P

I can now see how allocating a pointer (using new or malloc()) would fail, but if the structure being pointed to were allocated in main and modified in the function, would that also fail?


Modifying the memory pointed to will work as expected. The only difficulty is when the function needs to modify the "head" of the list (e.g. inserting an element at the front of the list.) In that case we need to use indirection or pass by reference to achieve the desired result. Alternately, returning the "head" pointer from the function can work, but that requires the client code to religiously adopt the return value, and programmers are adept at ignoring return values.
Last edited on
Thanks for the help. before i fixed the warnings the program ran the interface then it had the seg fault. Now that i fixed it the program gives me the seg fault as soon as i run the program. I think the error is in the function call to readFile().

this is the call:
 
 readFile( &record, argv[1], &numStudents );


any help on what is wrong here?
argv[1], like cire and I were discussing. Also, your else block has no braces {} so it'll execute no matter what argc is. Try this:

1
2
3
4
5
6
7
8
9
10
11
// see if filename is in argv
if( argc > 1 )
{               
    //call function to read from file
    readFile( &record, argv[1], &numStudents );
}
else
{
    cerr << "No file name included\n";
    exit( EXIT_FAILURE );      // end program after printing error
}


Last edited on
Topic archived. No new replies allowed.