I have a code snippet below from an exercise I’m working on. It reads a CSV and enters it into a linked list then prints to the console. The CSV looks like this:
5,3,19
7,12,2
13,15,25
22,0,7
It compiles using both Visual Studio 2010 and G++ in both Linux and Windows. The binary executes in the Windows XP command prompt but a segmentation fault occurs when run in Git Bash (Windows XP) and under Linux. Using a debugger (under Linux) I’ve isolated the problem to printList() not recognising the end of the linked list.
Why is this occurring and what can I do to prevent it? Any suggestions would be greatly appreciated.
#include <cstdlib>
#include <sstream>
#include <iostream>
#include <fstream>
using namespace std;
// CSV source file parameters
const char *cSourceCSV = "source.csv";
const int iFieldsPerRow = 3;
enum direction_t {UP=1, STATIONARY=0, DOWN=-1};
// struct to hold data in a singly linked list
struct CallList {
float fTime; // time of call in seconds from beginning
int iFromPos;
int iToPos;
direction_t d_tDirectionWanted();
CallList *next;
};
direction_t CallList::d_tDirectionWanted() {
int iBalance = iFromPos - iToPos;
direction_t d_tDirection;
if (iBalance < 0) d_tDirection = DOWN;
else if (iBalance == 0) d_tDirection = STATIONARY;
else if (iBalance > 0) d_tDirection = UP;
return d_tDirection;
}
CallList *head;
CallList *temp;
CallList *work;
void populateList(const char *cSourceCSV) {
string sRow;
string sValue;
ifstream ioSource (cSourceCSV); // the source file placed in an input stream
if (ioSource.is_open()) { // making sure the stream/file is open
while (ioSource.good()) { // repeat while stream is still healthy
// obtain the data
temp = new CallList;
getline (ioSource,sRow); // reading each row of data
stringstream s_sRow(sRow); // now entering the row into a stringstream
for (int i=0; i<iFieldsPerRow; i++) {
ws(s_sRow); // if there is whitespace in s_sRow remove it <-this is
// stopping the program from crashing but I get an extra line 1,1,1
getline (s_sRow,sValue,','); // now getting the data from the
// stringstream using the comma as a delimiter
if (i==0) {
temp->fTime = stof(sValue);
}
else if (i==1) {
temp->iFromPos = stoi(sValue);
}
else if (i==2) {
temp->iToPos = stoi(sValue);
}
}
// the stationary calls are excluded
if (temp->d_tDirectionWanted() == STATIONARY) continue;
// place the remaining data in the linked list
if (head == NULL) {
// insert the head
head = temp;
}
else {
//********* THIS WORKS *************
work = head;
// nothing fancy needed here as list is already in time order
while(work != NULL) {
if (work->next == NULL) {
work->next = temp;
break;
}
work = work->next;
}
}
//************************************
}
ioSource.close();
}
else cout << "Error opening file: " << cSourceCSV << endl;
return;
}
//********* BUT THIS DOESN'T, WHY? *************
void printList(){
work = head;
while (work != NULL) {
printf("Time: %*.1f, From: %*i, To: %*i, Dir: %*i\n", 5, work->fTime, 2, work->iFromPos, 2, work->iToPos, 2, work->d_tDirectionWanted());
if (work->next == NULL) break;
else work = work->next;
}
return;
}
//************************************
int main(int argc, char *argv[]) {
populateList(cSourceCSV);
printList();
return 0;
}
When you allocate your CallList node the first time, set the
nextfield to null.Your
printListtraverses the list untilworkisNULLbutworkgets its value from thenextfield of your list nodes which are never initialized. When it gets to the end, the last node contains garbage in thenextfield and your program dies.Why this is OK on Windows and not on Linux is an artifact of Undefined Behavior which is what you get when you try to access an uninitialized variable.