So I am working on a college assignment, and the professor uses a Linux based system to run our code. So, I installed Ubuntu on a VM and setup codeblocks. The following code runs perfectly on Visual Studio 2010 on my Host Windows 7, but I get a Segmentation Fault (Core Dumped) error when it runs. I've never seen this error before and even after looking o Google I still can't seem to find the problem. Anyone see something I do not? NOTE: If more code is required let me know. Also, FYI the second constructor is the only one that is "called" upon creation. Code (Text): #include "Maze.h" #include "Position.h" #include "DStackT.h" #include <iostream> #include <cassert> using namespace std; // FILL IN THE MISSING CODE // Hint Question. For stack: what is the longest possible path in a maze? Maze::Maze() { size = MAZEMAX; // allocate memory for the first pointer M = new state*[size]; // allocate memory for each pointer for (int I = 0; I < size; ++I) M[I] = new state[size]; // set the entire maze to a wall for(int I = 1; I < size; I++) // row { for (int j = 1; j < size; j ++) // column { Position p(I,j); // create a Position object setState(p,WALL); // set the sate at the current position as a Wall } } // set start position to upper left corner start = Position(1,1); // set exit position to the bottom right corner exit = Position(size,size); } // constructor with a parameter that tells the maze how large it is. // max is used as height and width Maze::Maze(int max) { size = max; // set the max size // allocate memory for the first pointer M = new state*[size]; // allocate memory for each pointer for (int I = 0; I < size; ++I) M[I] = new state[size]; // set the entire maze to a wall for(int I = 1; I < size; I++) // row { for (int j = 1; j < size; j ++) // column { Position p(I,j); // create a Position object setState(p,WALL); // set the sate at the current position as a Wall } } // set start position to upper left corner start = Position(1,1); // set exit position to the bottom right corner exit = Position(size,size); } // an unused constructor Maze::Maze(Position s, Position e, int n) { size = n; // set the max size // allocate memory for the first pointer M = new state*[size]; // allocate memory for each pointer for (int I = 0; I < size; ++I) M[I] = new state[size]; // set the entire maze to a wall for(int I = 1; I < size; I++) // row { for (int j = 1; j < size; j ++) // column { Position p(I,j); // create a Position object setState(p,WALL); // set the sate at the current position as a Wall } } // set start position start = s; // set exit position exit = e; } // gets the state of a position state Maze::getState(const Position &P) const { return M[P.getRow()][P.getCol()]; } // displays the maze on screen void Maze::display(ostream &out) const { out << '\n'; // loop through each position in the maze for (int I=0; I < size;I++) { for (int j=0; j < size; j++) if (Position(I,j) == start) // if this is the start position cout << 's'; // put a s else if (Position(I,j) == exit) // if this is the exit then cout << 'e'; // put an e else if (M[I][j] == WALL) // if it is a wall out << '*'; // put a * else // otherwise out << ' '; // put a space out << '\n'; } out << '\n'; } // set the state of the position in maze void Maze::setState(const Position &P, state s) { int I = P.getRow(); // get the row of the current position int j = P.getCol(); // get the column of the current position // make sure the user didn't put in values that are out of range assert(1 <= I && I <= size && 1 <= j && j <= size); // set state M[I][j] = s; } // finds the path to the exit of the maze bool Maze::findExit() { Position current; // current position of the mouse Position next; // position to look at int currentState; // get beginning position path.push(start); current = path.top(); // loop until at the exit while (current.getCol() != exit.getCol() || current.getRow() != exit.getRow()) { // loop through all the directions for (int I = 0; I < NONE; I++) { // get the next state currentState = getState(current.Neighbor((const direction&)I)); switch(currentState) { case WALL: // if it's a wall // check to see if the stack is empty if (path.empty()) return false; // if it is, then there was no exit break; // leave case VISITED: // if we have already been there... // first, make sure there are no open spots around if((getState(current.Neighbor(UP)) != OPEN) && (getState(current.Neighbor(LEFT)) != OPEN) && (getState(current.Neighbor(DOWN)) != OPEN) && (getState(current.Neighbor(RIGHT)) != OPEN)) { // go back a space path.pop(); M[current.getRow()][current.getCol()] = VISITED; // check to see if the stack is empty if (path.empty()) return false; // if it is, then there was no exit current = path.top(); // get the new position I = NONE; // reset "for loop" } break; case OPEN: // set position to VISITED M[current.getRow()][current.getCol()] = VISITED; // add position to the stack path.push(current.Neighbor((const direction&)I)); // set current position to new position current = path.top(); // check if this position is the exit if(current == exit) return true; // exit was found I = NONE; // reset "for loop" break; } //switch } // for loop }// while loop // NOTE: should never actually get here return false; // no exit } void Maze::printPath() { Position P; // create a position object Stack<Position> T(size*size); // create a Stack of Position // loop until the path stack is empty, // copy the path stack while (!path.empty()) { T.push(path.top()); path.pop(); } while (!T.empty()) { cout << T.top() << '\n'; T.pop(); } } void Maze::initialize() // Assumes size already set { int I, j; cout << "All position indices k must satisfy 1 <= k < = " << (size-1) << '\n'; cout << "Enter the start position:\n"; cin >> start; cout << "Enter the exit position:\n"; cin >> exit; cout << "Please enter column indices for each row\n"; for (I = 1; I < size-1; I++) { cout << "row " << I << ": "; cin >> j; while (j > 0){ M[I][j] = OPEN; cin >> j; }; } if (getState(start) != OPEN) { cout << "start position must be open; will fix that now\n"; M[start.getRow()][start.getCol()] = OPEN; } if (getState(exit) != OPEN) cout << "Boy, are you mean, setting the exit in the wall. Poor Remy!\n"; cout << "Maze entry complete\n"; }
Segmentation fault usually means you wrote to memory outside the bounds of an array. If you use a debugger (such as the one in Visual Studio), you can find the line where the program crashed, which should hint as to what your issue is. Taking a glance at your code, however: Code (Text): M = new state*[size]; This shouldn't have compiled because the * is just there where it shouldn't be. Did you mean Code (Text): M = new state[size]; ?
No, it looks like M is a two-dimensional array. That line is perfectly valid code because it's allocating an array of pointers to 'state', then in the next few lines it's iterating through each pointer and allocating an array of 'state' objects, thus forming the 2D array. But yeah, the error means that you're writing to memory you shouldn't be writing to, or perhaps dereferencing an invalid pointer. Another way to debug this (besides using a debugger) is to insert print statements to print your indexes. Make sure everything is in bounds.
M is a double pointer located in the Maze class: Code (Text): state **M; // two-dimensional array of state values I am not sure how else to allocate a multi-dimensional array from a double pointer. And unfortunately, that code I posted is the only one I am allowed to modify. EDIT: I'll try that, I can't get that debugger to run in codeblocks so I'll try the print method. Thanks Delta.
The new line still isn't valid because the * should be before the type name, not after: Code (Text): M = new *state[size]; unless C++ changed its rules...?
Nope. In C++, for a dynamically allocated array of pointers, the asterisk goes after. It's in the format of Code (Text): a = new type[elements]; In this particular case, the type happens to be 'pointer to state' which would be written as 'state *'. Therefore, asterisk goes after. It only goes before if you're dereferencing a pointer, declaring a static array, or declaring a single pointer variable, I.e. Code (Text): mytype *p1, *p2[100], *p3;
Well, I got it fixed. It was going out of the array bounds. Funny how Visual Studio "fixes" this on it's own. But at least it run under Linux now. I learn something new about C++ everyday. Thanks for all the help!
No prob. I don't think Visual Studio was necessarily "fixing" anything. The exact behavior when writing out of bounds of an array is undefined. In practice, it depends on the layout of memory. I'd guess that Microsoft's compiler/runtime laid out memory in such a way that there was valid data immediately before or after the array; perhaps some other variable or what have you. So writing out of bounds would have corrupted some random program data elsewhere. You only get an error if you write/dereference outside of the program's allocated area of memory, which isn't always true when going out of array bounds.