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.

Attachments
#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

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?

Comments
Good clarification!

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;
}

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.

This article has been dead for over six months. Start a new discussion instead.