I'm trying to traverse to the end of a linked list, but I get a segmentation fault when my while loop checks to see if the "next" pointer is null. Any suggestions on how to perform this check without causing a segmentation fault would be greatly appreciated.
Daria Shmaria 0 Light Poster
#include "listNode.h"
#include <iostream>
#include "segment.h"
using namespace std;
ListNode::ListNode()
{
ListNode::next = NULL;
}
ListNode::~ListNode()
{
// destruct
}
// change which segment the ListNode contains
int ListNode::changeSeg(Segment * inputSeg)
{
ListNode::seg.changeBegin(inputSeg->returnBegin());
ListNode::seg.changeEnd(inputSeg->returnEnd());
ListNode::seg.changeDist(inputSeg->returnDist());
ListNode::seg.changeSpeed(inputSeg->returnSpeed());
return 0;
}
int ListNode::changeNext(ListNode * inputNext)
{
ListNode::next = inputNext;
return 0;
}
ListNode * ListNode::returnNext()
{
ListNode * nextCopy;
nextCopy = ListNode::next;
return nextCopy;
}
int ListNode::returnSegBegin()
{
int segBegin = ListNode::seg.returnBegin();
cout << "returnSegBegin() says segBegin = " << segBegin << endl;
return segBegin;
}
int ListNode::returnSegEnd()
{
int segEnd = ListNode::seg.returnEnd();
cout << "returnSegEnd() says segEnd = " << segEnd << endl;
return segEnd;
}
#ifndef _LISTNODE_H
#define _LISTNODE_H
#include "segment.h"
class ListNode
{
public:
ListNode();
~ListNode();
int changeSeg(Segment * inputSeg);
int changeNext(ListNode * inputNext);
ListNode * returnNext();
int returnSegBegin();
int returnSegEnd();
private:
ListNode * next;
Segment seg;
};
#endif
#include <iostream>
#include <fstream>
#include <string.h>
#include <sstream>
#include "vertex.h"
#include "listNode.h"
// segment.h is not included because it is included in vertex.h
using namespace std;
int main(int argc, char** argv)
{
if(argc != 4) // check for the correct number of inputs
{
cerr << "Incorrect number of inputs." << endl;
return -1;
}
// Read the location file
int numLocations = 0;
int vertexNumber = 0;
Vertex ** al; // declare the adjacency list
ifstream myLocations(argv[1]);
if(myLocations)
{
string locLine;
string junkR;
while(getline(myLocations, locLine, '\r')) // break the file into lines
{
getline(myLocations, junkR, '\n'); // remove the first character (\n) from each line
char * convline = new char[locLine.size() + 1]; // convert string to char *
strcpy(convline, locLine.c_str());
if(locLine.empty() == 1) // ignore empty strings
{
cout << "Empty line ignored." << endl;
}
else
{
if(convline[0] != '#') // add locations to the graph
{
if(numLocations == 0) // check for the line containing the number of locations
{
numLocations = atoi(convline);
cout << "numLocations = " << numLocations << endl;
al = new Vertex * [numLocations];
}
else
{
cout << "Add the line to the graph: \t" << convline << endl;
// set the first value of the adjacency list to a new vertex
Vertex * v; // should this be a pointer or not?
v = new Vertex;
v->changeName(convline);
cout << "vertex v made" << endl;
// set the ID of the vertex
v->changeID(vertexNumber);
// "insert" the vertex into the adjacency list (with pointers)
al[vertexNumber] = v;
vertexNumber++;
}
}
else // ignore comments
{
cout << "Comment ignored." << endl;
}
}
// delete locLine
cout << endl;
}
}
else if(!myLocations) // if the location file can't be read, error and exit
{
cerr << "The locations file could not be read." << endl;
exit(2);
}
// Read the segment file
int numSegments = 0;
ifstream mySegments(argv[2]);
if(mySegments)
{
string segLine;
string junkR;
while(getline(mySegments, segLine, '\r')) // break the file into lines
{
getline(mySegments, junkR, '\n'); // remove the first character (\n) from each line
char * csegline = new char[segLine.size() + 1]; // convert string to char *
strcpy(csegline, segLine.c_str());
if(segLine.empty() == 1) // ignore empty strings
{
cout << "Empty line ignored." << endl;
}
else
{
if(csegline[0] != '#') // add locations to the graph
{
if(numSegments == 0) // check for the line containing the number of locations
{
numSegments = atoi(csegline);
cout << "numSegments = " << numSegments << endl;
}
else
{
cout << "Add the segment to the graph: \t" << csegline << endl;
Segment * s;
s = new Segment;
string sBegin;
string sEnd;
string sDist;
string sSpeed;
// break line into tokens:
stringstream lineStream(segLine);
// vertex number where segment begins
lineStream >> sBegin;
char * cBegin = new char[sBegin.size() + 1];
strcpy(cBegin, sBegin.c_str());
int begin = atoi(cBegin);
cout << "begin = " << begin << endl;
// vertex number where segment ends
lineStream >> sEnd;
char * cEnd = new char[sEnd.size() + 1];
strcpy(cEnd, sEnd.c_str());
int end = atoi(cEnd);
cout << "end = " << end << endl;
// distance covered by segment
lineStream >> sDist;
char * cDist = new char[sDist.size() + 1];
strcpy(cDist, sDist.c_str());
float dist = atof(cDist);
cout << "dist = " << dist << endl;
// speed of traffic on segment
lineStream >> sSpeed;
char * cSpeed = new char[sSpeed.size() + 1];
strcpy(cSpeed, sSpeed.c_str());
float speed = atof(cSpeed);
cout << "speed = " << speed << endl;
// store values in segment
s->changeBegin(begin);
s->changeEnd(end);
s->changeDist(dist);
s->changeSpeed(speed);
// create a new ListNode to hold the segment
ListNode * ln; // how to avoid scope problems?
ln = new ListNode;
// put the segment inside the new ListNode
ln->changeSeg(s);
ln->returnSegBegin();
ln->returnSegEnd();
// put the new ListNode at the end of the list of the beginning vertex
ListNode * current; // pointer to current list node
current = al[begin]->returnFirstListNode();
// while the current ListNode's next pointer is not NULL, advance to the next ListNode
while(current->returnNext() != NULL)
{
// skip to the next node
current = current->returnNext();
}
cout << "After while(current != NULL loop)" << endl;
//cout << "current node's next = " << current->returnNext() << endl; // CAUSES SEGMENTATION FAULT
// set that node's next value equal to the list node
//current->changeNext(ln); // CAUSES SEGMENTATION FAULT
// attach segment to adjacency list
// the last item in the edgelist member of al[begin] should point to the
//while(al[begin]->edgeList->next != NULL)
// {
// go to the next one in the list
// }
// once you've found the end of the list
//
// delete char * cBegin, cEnd, cDist, cSpeed
// delete the segment s? its values should be copied over to the al's segment
}
}
else // ignore comments
{
cout << "Comment ignored." << endl;
}
}
// delete cSegline
cout << endl;
}
}
else if(!mySegments) // if the segment file can't be read, error and exit
{
cerr << "The segments file could not be read." << endl;
exit(3);
}
// Read in the trip request file
int numTrips = 0;
ifstream myTrips(argv[3]);
if(myTrips)
{
string tripLine;
string junkR;
while(getline(myTrips, tripLine, '\r')) // break the file into lines
{
getline(myTrips, junkR, '\n'); // remove the first character (\n) from each line
char * ctripline = new char[tripLine.size() + 1]; // convert string to char *
strcpy(ctripline, tripLine.c_str());
if(tripLine.empty() == 1) // ignore empty strings
{
cout << "Empty line ignored." << endl;
}
else
{
if(ctripline[0] != '#') // add locations to the graph
{
if(numTrips == 0) // check for the line containing the number of locations
{
numTrips = atoi(ctripline);
cout << "numTrips = " << numTrips << endl;
}
else
{
cout << "Processing this trip request: \t" << ctripline << endl;
}
}
else // ignore comments
{
cout << "Comment ignored." << endl;
}
}
// delete tripLine
cout << endl;
}
}
else if(!myTrips) // if the trip request file can't be read, error and exit
{
cerr << "The trip request file could not be read." << endl;
exit(4);
}
/*
// returning each vertex's name and ID
for(int i = 0; i < numLocations; i++)
{
al[i]->returnName();
cout << endl;
al[i]->returnID();
cout << endl;
}
*/
// deallocate the new char *s from reading in the input files
// traverse list to delete each value in al and the lists it points to
// otherwise there will be many memory leaks
delete al;
cout << "the end of main" << endl;
return 0;
}
#include "segment.h"
#include <iostream>
using namespace std;
Segment::Segment()
{
Segment::begin = -1;
Segment::end = -2;
Segment::dist = -1;
Segment::speed = -1;
}
Segment::~Segment()
{
// destruct things
}
int Segment::changeBegin(int b)
{
Segment::begin = b;
//cout << "begin is now " << Segment::begin << endl;
return 0;
}
int Segment::changeEnd(int e)
{
Segment::end = e;
//cout << "end is now " << Segment::end << endl;
return 0;
}
int Segment::changeDist(float d)
{
Segment::dist = d;
//cout << "dist is now " << Segment::dist << endl;
return 0;
}
int Segment::changeSpeed(float s)
{
Segment::speed = s;
//cout << "speed is now " << Segment::speed << endl;
return 0;
}
int Segment::returnBegin()
{
int beginCopy = Segment::begin;
return beginCopy;
}
int Segment::returnEnd()
{
int endCopy = Segment::end;
return endCopy;
}
float Segment::returnDist()
{
float distCopy = Segment::dist;
return distCopy;
}
float Segment::returnSpeed()
{
float speedCopy = Segment::speed;
return speedCopy;
}
#ifndef _SEGMENT_H
#define _SEGMENT_H
class Segment
{
public:
Segment();
~Segment();
int changeBegin(int b);
int changeEnd(int e);
int changeDist(float d);
int changeSpeed(float s);
int returnBegin();
int returnEnd();
float returnDist();
float returnSpeed();
private:
int begin;
int end;
float dist;
float speed;
};
#endif
#include "vertex.h"
#include <iostream>
using namespace std;
Vertex::Vertex()
{
// do something
Vertex::firstListNode = NULL;
}
Vertex::~Vertex()
{
// destruct things
}
int Vertex::changeName(char * inputname)
{
int length;
length = strlen(inputname);
Vertex::name = (char *) malloc (length);
strcpy(Vertex::name, inputname);
return 0;
}
char * Vertex::returnName()
{
char * namecopy;
int length;
length = strlen(Vertex::name);
namecopy = (char *) malloc (length);
strcpy(namecopy, Vertex::name);
cout << "returnName() called on " << namecopy << endl;
return namecopy;
}
int Vertex::changeID(int IDinput)
{
Vertex::ID = IDinput;
return 0;
}
int Vertex::returnID()
{
cout << "returnID() called on ID " << Vertex::ID << endl;
return Vertex::ID;
}
ListNode * Vertex::returnFirstListNode()
{
ListNode * firstListNodeCopy;
firstListNodeCopy = Vertex::firstListNode;
return firstListNodeCopy;
}
#ifndef _VERTEX_H
#define _VERTEX_H
#include "segment.h"
#include "listNode.h"
class Vertex
{
public:
Vertex(); // constructor
~Vertex(); // destructor
int changeName(char *);
char * returnName();
int changeID(int IDinput);
int returnID();
ListNode * returnFirstListNode();
private:
char * name;
int ID; // is this necessary or does the location in the adjacency list serve as ID?
ListNode * firstListNode;
};
#endif
ArkM 1,090 Postaholic
It's legal to compare any pointer value with null pointer or any others pointer values of the same type.
Better post your code fragment with segmentation fault. It's annoying to download the whole source, didn't you understand it?
tux4life commented: Good clarification! +7
Daria Shmaria 0 Light Poster
Sorry for the annoyance. I posted everything because I wasn't sure that a code fragment would be understandable due to the number of classes functions that I wrote myself.
Vertex ** al; // declare the adjacency list
al = new Vertex * [numLocations];
ListNode * current; // pointer to current list node
current = al[begin]->returnFirstListNode();
// while the current ListNode's next pointer is not NULL, advance to the next ListNode
while(current->returnNext() != NULL) // comparison causes segmentation fault
{
// skip to the next node
current = current->returnNext();
}
// in the ListNode class:
ListNode * ListNode::returnNext()
{
ListNode * nextCopy;
nextCopy = ListNode::next; // ListNode::next is a pointer to the next ListNode in the list
return nextCopy;
}
ArkM 1,090 Postaholic
There are lots of possible causes, for example:
- value of begin index is out of range
- current == 0 before while loop for empty list
- memory corruption
...
The last point: Vertex::changeName is wrong:
int Vertex::changeName(char * inputname) // const char* !
{
int length; // better size_t or unsigned type
length = strlen(inputname); // forgot to count zero byte
Vertex::name = (char *) malloc (length); // no room for zero byte
strcpy(Vertex::name, inputname); // 100% memory corruption
return 0; // why? better void changeName
}
Stop using dynamically allocated C-strings! You will never debug this code with awkward and error-prone sequences of malloc/new-strcpy. Use std::string for string data.
Stop using mix of malloc/new! Use new/delete only in C++ programs! Don't use non-standard strdup function!
It's impossible to run your code (no external files). Next time make zipped attachment (a single compact file) to your posts.
Be a part of the DaniWeb community
We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.