• Advertisement
Sign in to follow this  

Problem returning pointer from method

This topic is 1958 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

I know this code is a mess and will have all types of NULL errors, but this is only the beginning and I haven't cleaned it up yet.

The only thing that I can't really figure out is why when the traverse method (which returns a pointer to a Location) is called, the program crashes.

I've tried putting in debug prints at various points in this method and so far have NOT gotten any consistent readout of the problem.

As I see it, it should initialize a sentinel pointer to ConnectionNode as the head of the list of Connections (a ConnectionNode) of the current Location, then traverse the list as long as the shortcut for the sentinel's current Connection is not equal to inputChar. Then when it finds a match it should return the Location pointer in the Connection for which the shortcut matched.


#include <iostream>
#include <string>
using namespace std;
class Location;
class Connection{
public:
string direction;
char shortcut;
string description;
Location* connectionDestination;
Connection(string constructorDirection, char constructorShortcut, string constructorDescription){
direction = constructorDirection;
shortcut = constructorShortcut;
description = constructorDescription;
connectionDestination = NULL;
}
};
struct ConnectionNode{
ConnectionNode* next;
Connection* data;
};
class Location{
public:
string name;
string description;
ConnectionNode* connectionListHead;
Location(string constructorName, string constructorDescription){
name = constructorName;
description = constructorDescription;
connectionListHead = NULL;
}
void AddConnection(Connection* connectionToAdd){
ConnectionNode*elem = new ConnectionNode;
elem->data = connectionToAdd;
//if the list of connections is currently NULL
if (connectionListHead == NULL){
elem->next = NULL;
connectionListHead = elem;
}
//add new connection to end of list
else{
elem->next = connectionListHead;
connectionListHead = elem;
}
}
Location*traverse(char inputChar){
ConnectionNode*elem = connectionListHead;
while(elem->data->shortcut != inputChar){
elem = elem->next;
}
return elem->data->connectionDestination;
}
};

int main(){
//create our world
Location*roomC1 = new Location("Empty corridor",
"You are in a dimly lit corridor with\npassageways to the north and west.");
Connection*linkC1toB1 = new Connection("West", 'w', "Passageway to the west");
roomC1->AddConnection(linkC1toB1);
Connection*linkC1toC2 = new Connection("North", 'n', "Passageway to the north");
roomC1->AddConnection(linkC1toC2);
//initialize game state variables
bool quit = 0;
char inputChar;
Location*currentRoom = roomC1;
ConnectionNode*currentConnection = NULL;

//main loop
while (!quit){
//display current room information
cout << endl << currentRoom->name << endl;
for (int i=0; i<currentRoom->name.length(); i++) cout << "-";
cout << endl << currentRoom->description << endl << endl;
currentConnection = currentRoom->connectionListHead;
//list all the connections to currentRoom
while (currentConnection != NULL){
cout << "-> " << currentConnection->data->direction
<< " [" << currentConnection->data->shortcut << "]"
<< " - " << currentConnection->data->description << endl;
currentConnection = currentConnection->next;
}
cout << "-> Quit [q] - Exit game (progress will be lost)" << endl;
cin >> inputChar;
//set currentRoom equal to a pointer to the room whose connectionNode in the
//current room has shortcut == inputChar
if (inputChar == 'q') quit = 1;
else{
currentRoom = currentRoom->traverse(inputChar);
}
}
}

Share this post


Link to post
Share on other sites
Advertisement
There is nothing setting connectionDestination to anything other than NULL in that code. So the traverse method returns NULL, so currentRoom becomes NULL and your program crashes.

Share this post


Link to post
Share on other sites
Here's a modified version of your code that is closer to how I would have written it, in case it helps you. I chose to identify locations by name, and I made the world a map from name to location. If you were thinking of having multiple locations with identical names, you may want to add the name back into the location and use a `code' instead as the identifier.

#include <iostream>
#include <string>
#include <vector>
#include <map>

struct Connection {
std::string direction;
char shortcut;
std::string description;
std::string destination;

Connection(std::string direction, char shortcut, std::string description, std::string destination)
: direction(direction),
shortcut(shortcut),
description(description),
destination(destination) {
}
};

struct Location {
std::string description;
std::vector<Connection> connections;

Location(std::string description = "")
: description(description) {
}
};

int main(){
// Create our world (FIXME: This should come from a file)
std::map<std::string, Location> world;
world["Empty corridor"] = Location("You are in a dimly lit corridor with passageways to the north and west.");
world["Empty corridor"].connections.push_back(Connection("West", 'w', "Passageway to the West", "West room"));
world["Empty corridor"].connections.push_back(Connection("North", 'n', "Passageway to the North", "North room"));
world["West room"] = Location("This is the room to the West of the corridor."); // Not feeling creative :)
world["West room"].connections.push_back(Connection("East", 'e', "Back to the corridor", "Empty corridor"));
world["North room"] = Location("This is the room to the North of the corridor.");
world["North room"].connections.push_back(Connection("South", 's', "Back to the corridor", "Empty corridor"));

// Initialize game state variables
std::string current_location_name("Empty corridor");

// Main loop
for (;;) {
Location const &current_location = world[current_location_name];

// Display current location information
std::cout << current_location_name << '\n';
for (int i=0, end=current_location_name.length(); i!=end; ++i)
std::cout << '-';
std::cout << '\n';
std::cout << current_location.description << "\n\n";

// List all the connections to current_location
for (int i=0, end=current_location.connections.size(); i!=end; ++i) {
Connection const &connection = current_location.connections;
std::cout << "-> " << connection.direction
<< " [" << connection.shortcut << "]"
<< " - " << connection.description << '\n';
}
std::cout << "-> Quit [q] - Exit game (progress will be lost)" << std::endl;

// Get and process input. NOTE: Move this to a function to make code more clear, and to appease goto haters. :)
while (1) {
std::string input;
if (!std::getline(std::cin, input))
goto QUIT;

char input_char = input[0];

if (input_char == 'q')
goto QUIT;

// Find the connection whose shortcur matches input_char and move there
for (int i=0, end=current_location.connections.size(); i!=end; ++i) {
Connection const &connection = current_location.connections;
if (connection.shortcut == input_char) {
current_location_name = connection.destination;
goto CONNECTION_FOUND;
}
}
std::cout << "Unrecognized input!\n";
std::cin.clear();
}

CONNECTION_FOUND:;
}
QUIT:;
}
Edited by Álvaro

Share this post


Link to post
Share on other sites
To be honest, I didn't dive too deep into the code, but the problem is that the connectionDestination of the Connection is never initialized (except for the NULL initialization in the Connection constructor). So at the end of the traverse method it will always return a NULL pointer, so currentRoom is NULL after calling traverse.

[EDIT] Damn... forgot to refresh. I opened the topic about two hours ago but then was away from the computer for a while... Edited by brx

Share this post


Link to post
Share on other sites
But thank you for taking the time, brx.

And thanks a ton for the code rewrite Alvaro. I'll be pouring over it and doubtless learning a lot.

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement