I am trying to build a simple text adventure for finals week.
It's pretty standard stuff. Use 'n', 'e', 's', and 'w' to traverse the house, and try to get to the end of the maze.
All was going well for a while, but I'm running into a problem when I try to retrieve a list of available doors.
Here's my basic setup
class Node
{
public:
//...
Node* getNLink() {return northLink;}
Node* getELink() {return eastLink;}
Node* getSLink() {return southLink;}
Node* getWLink() {return westLink;}
//...
void printAllPossibleMoves();
//checks all four links and tells the user which ones are not set to NULL
private:
//...
Node* northLink;
Node* eastLink;
Node* southLink;
Node* westLink;
const string dirNodeToStr(Node* dirNode);
//Takes a node pointer and returns whether that link is n/e/s/w, no spaces
};
I have snipped out all of the superfluous members.
My problem comes from the two member functions in the Node class.
First, printAllPossibleMoves() gets a list of all pointers that are not set to NULL and feeds those pointers to dirNodeToStr() one-by-one
void Node::printAllPossibleMoves()
{
Node* allDoors[4] = {getNLink(), getELink(), getSLink(), getWLink()};
//gets a list of all four pointers
Node* availableDoors[4];
int allDoorsLen(4), availableDoorsLen(0);
for(int i=0; i<allDoorsLen; i++)
{
if(allDoors[i] != NULL)
{
//filters out any NULL pointers and keeps track of the # of non-NULL pointers
availableDoors[i] = allDoors[i];
availableDoorsLen++;
}
}
if(availableDoorsLen == 0)
cout << "You don't see any doors in this room. Odd" << endl;
else if(availableDoorsLen == 1)
cout << "You see a door to the " << dirNodeToStr(availableDoors[0]) << endl; //CALL 1
else if(availableDoorsLen > 1 )
{
cout << "You see doors to the ";
for(int j=0; j<availableDoorsLen; j++)
{//make sure to put an 'and' in there before the last direction is printed
if(j == (availableDoorsLen-1))
cout << " and " << dirNodeToStr(availableDoors[j]) << endl; //CALL 2
else
cout << " " << dirNodeToStr(availableDoors[j]); //CALL 3
}
}
}
On the three marked lines, printAllPossibleMoves() passes one of the Node pointers to dirNodeToStr(), which is where the error manifests itself.
const string Node::dirNodeToStr(Node* dirNode)
{
if(dirNode == dirNode->getNLink())
return "north";
else if(dirNode == dirNode->getELink())
return "east";
else if(dirNode == dirNode->getSLink())
return "south";
else if(dirNode == dirNode->getWLink())
return "west";
else
{
cout << "Error at Node::dirNodeToStr: Function was fed an invalid parameter" << endl;
//whenever this function is called, it falls through to this case
system("PAUSE");
exit(0);
}
}
And the output:
This is the guest bedroom.
n
WEST HALL
This is a hallway.
You see doors to the Error at Node::dirNodeToStr: Function was fed an invalid pa
rameter
Press any key to continue . . .
And in case it matters, here's the original function call
void Node::movePlayer(Node*& pos, string direction)
{
if(direction == "north")
{
if(northLink == NULL)
cout << "You can't go north.\n";
else
{
pos = getNLink();
cout << pos->getRoomName() << endl << pos->getRoomInfo() << endl;
pos->printAllPossibleMoves();
}
}
//...
}
So what do you think? Why do the pointers not match up? I collected all of the pointers, fed them into another function, and then compared one of them to a list of all of the same pointers. Shouldn't this one be a no-brainer?
This code
for(int i=0; i<allDoorsLen; i++)
{
if(allDoors[i] != NULL)
{
//filters out any NULL pointers and keeps track of the # of non-NULL pointers
availableDoors[i] = allDoors[i];
availableDoorsLen++;
}
}
Is causing NULLs to be placed in your availableDoors, I think you can fix this by changing the line
availableDoors[i] = allDoors[i]
To
availableDoors[availableDoorsLen] = allDoors[i]
Related
Question: I keep receiving exc_bad_access (process code 11) error. Is this due to a bad algorithm or simply a coding error? Can anyone help me fix it?
My class assignment is to create a binary search tree whose nodes can store a name, a balance, and a key. Nodes are to be organized and searched for using the key. This tree should support insertion, inorder traversal, and searching based on a key (I haven't built this function yet). I've also included several other functions to facilitate building these. If it matters, I'm using CLion on OSX High Sierra. Additionally, I get the error on the first prompt to enter node information, the error does not seem to be related to the input itself.
//Genghis Khan
#include <iostream>
#include <vector>
using namespace std;
class node
{
public:
int key;
string name;
double balance;
node *leftptr;
node *rightptr;
friend class tree;
};
class tree
{
public:
node *root, *temp, *v;
//Constructor
tree()
{
root = NULL;
temp = root;
}
bool empty()
{
return(root == NULL);
}
bool isleaf(node *x)
{
return((x->leftptr == NULL) && (x->rightptr == NULL));
}
void inorder(node *temp)
{
if(~isleaf(temp))
{
inorder(temp->leftptr);
cout << "Name: " << temp->name << " " << "Balance: " <<
temp->balance << " " << "Key: " << temp->key;
inorder(temp->rightptr);
}
}
node* createnode()
{
v = new node;
cout << "Enter name (string): " << endl;
getline(cin, v->name);
cout << "Enter key (integer): " << endl;
cin >> v->key;
cout << "Enter balance (double): " << endl;
cin >> v->balance;
return(v);
}
void set()
{
temp = root;
}
void insert(node *v)
{
while(~isleaf(temp))
{
if((v->key < temp->key))
{
temp = temp->leftptr;
insert(v);
}
else if(v->key > temp->key)
{
temp = temp->rightptr;
insert(v);
}
}
temp->key = v->key;
temp->balance = v->balance;
temp->name = v->name;
}
};
int main()
{
int n;
cout << "Enter number of people: ";
cin >> n;
//Creating instance of tree, inserting all data into tree
tree b;
for(int i = 0; i < n; i++)
{
b.set();
node *a = b.createnode();
b.insert(a);
}
//inorder part
b.set();
b.inorder(b.temp);
}
The functions are (pseudocode):
1. function isleaf(x): return(x's left pointer and x's right pointer are both NULL)
2. function set(): set temp to root //temp will be reset every time an insertion, traversal, or search occurs
3. function createnode():
v is a new node
get all the fields for v
return v
4. function insert(v)
while(not isleaf(temp)):
-if(v's key < temp's key)
temp = temp's left pointer (to the lower value child node)
insert(node *v)
-if(v's key > temp's key)
temp = temp's right pointer (to the higher value child node)
insert(node *v)
end while
duplicate v's data to temp, now that temp is a leaf
5. function inorder(temp):
if(not isleaf(temp):
inorder(temp's left pointer)
output all info in temp node
inorder(temp's right pointer)
Main Algorithm
for the number of nodes to be entered:
1. set
2. node *a = createnode
3. insert(a)
Update
The error seems to be coming from the 'if((v->key < temp->key))' line.
EXC_BAD_ACCESS just means that you are trying to access an invalid memory. By a quick brief, your function isleaf doesn't check whether x is null.
May have other errors, you can debug and find it by yourself.
I need some help with my code. The function findNode lies within a header file, and is called in the main. As you can see, findNode calls itself until it finds the correct data value in each of the nodes. The type of tree implemented is a General Tree.
My problem is that the function does find the TreeNode it needs to find, but it returns it incorrectly. The data value of p in main is empty
TreeNode<Type>* findNode(Type &_data, TreeNode<Type>* _ptr)
{
if(_ptr->data == _data)
{
cout << "ptr->data: " << _ptr->showData() << endl;
return _ptr;
}
if(_ptr->children != NULL)
{
findNode(_data, _ptr->children->getHead());
}
if(_ptr->getNext() != NULL)
{
findNode(_data, _ptr->getNext());
}
}
In MAIN:
.
.
case 3:
{
string data;
cout << "****************" << endl;
cout << "***findNode()***" << endl;
cout << "Data to find: " << endl;
cin >> data;
TreeNode<string>* p = Tree->findNode(data, Tree->getRoot());
cout << "p->data = " << p->showData() << endl;
break;
}
add "return" in front of findNode(..) to fix the issue.
if(_ptr->children != NULL)
{
return findNode(_data, _ptr->children->getHead());
}
if(_ptr->getNext() != NULL)
{
return findNode(_data, _ptr->getNext());
}
unless the data matches in the first time, it is not returned. it is merely called and the result is let go.
In your original code, Say the data is matched in 4 th level of function call:
findNode1->findNode2->findNode3->findNode4
then this happens:
findNode4 returns ptr to findNode3, which does not return anything as it just called the function without expecting any value back.
At your level of skill it is very good to practice "uniform coding" :
retval = _ptr;
}
else if(_ptr->children != NULL)
{
retval = findNode(_data, _ptr->children->getHead());
}
else if(_ptr->getNext() != NULL)
{
retval = findNode(_data, _ptr->getNext());
}
return retval; // return from single point.
it is merely a style not technically better, but imho gradual learning is better.
I am practicing some code implementing different data structures. For this example I am trying to implement a simple stack data structure. So far it works as intended, but I keep getting Hex characters when trying to display my stack. Could anyone help me with figuring out why this is the case?
Also I am trying to get better at structuring my code properly, can anyone that is already involved in the industry please give me some constructive criticism as to what I have coded so far. Thanks.
#include <iostream>
using namespace std;
// stack_MAX == maximum height of stack
const int stack_MAX = 10;
class stack{
public:
stack(){
//Constructor initializes top of stack
top = -1;
}
bool isFull(int top){
//isFull() will check to make sure stack is not full
//Will return TRUE if stack is FULL, and FALSE if
//stack is NOT FULL
if(top == stack_MAX - 1)
return true;
else
return false;
}
bool isEmpty(int top){
//isEmpty() will check to make sure stack is not empty
//Will return TRUE if stack is EMPTY, and FALSE if
//stack is NOT EMPTY
if(top == -1)
return true;
else
return false;
}
void push(int x){
//push() will push new element on top of stack
if(isFull(top)){
cout << "Sorry, but the stack is full!" << endl;
exit(1);
}
else{
top++;
x = stk[top];
}
}
void pop(){
//pop() will pop the top element from the stack
if(isEmpty(top)){
cout << "Sorry, but the stack is empty!" << endl;
exit(1);
}
else{
cout << stk[top] << " is being popped from stack!" << endl;
top--;
}
}
void display_stack(){
//diplay_stack() will show all elements currently in the stack
int temp; //will temporarily hold position of stack
temp = top;
while(!isEmpty(temp)){
cout << stk[temp] << endl;
temp--;
}
}
private:
int top;
int stk[stack_MAX];
};
int menu(){
int choice;
cout << "Welcome to my stack!" << endl;
cout << "What would you like to do? (select corresponding #)" << endl << endl;
cout << "1. Push" << endl;
cout << "2. Pop" << endl;
cout << "3. Display" << endl;
cout << "4. Quit" << endl;
cin >> choice;
return choice;
}
int main()
{
int selection, x;
stack myStack;
selection = menu();
while(selection != 4)
{
switch(selection){
case 1:
cout << "please enter number to be pushed: ";
cin >> x;
myStack.push(x);
selection = menu();
break;
case 2:
myStack.pop();
selection = menu();
break;
case 3:
myStack.display_stack();
selection = menu();
break;
default:
cout << "Oops that's not a selection, try again" << endl;
selection = menu();
break;
}
}
cout << "Thank you for stopping by and using my stack!" << endl;
system("pause");
return 0;
}
A statement in your push functin is wrong, modified as below:
void push(int x)
{
//push() will push new element on top of stack
if(isFull(top))
{
cout << "Sorry, but the stack is full!" << endl;
exit(1);
}
else
{
top++;
/***************************
x = stk[top];
****************************/
stk[top] = x;
}
}
Advice:
Learn to debug, here is the tutorial
Include the head file cstdlib when you want to use exit in your
code
Do not name your class with the same name for any classes in STL
As pointed out by prehistoric penguin, your push() function is incorrect:
x = stk[top];
Should be changed to:
stk[top] = x;
I wanted to comment anyway to offer some general comments as you requested:
If statements like this can be replaced by a single line of code:
if(top == stack_MAX - 1)
return true;
else
return false;
becomes:
return (stack_MAX - 1 == top);
Put constant expressions on the left-hand side of your comparison expression. For example:
(top == stack_MAX - 1)
becomes:
(stack_MAX - 1 == top)
The reason is that one day you will accidentally type something like:
(top = stack_MAX - 1)
and you or somebody else will waste a lot of time debugging it :)
Your isFull() and isEmpty() functions shouldn't take a parameter. They should just use the private member variable top. How would somebody call these functions without access to top, which you've correctly made a private member?
In general, avoid using. In my opinion it defeats the whole purpose of namespaces. using namespace std is a commonly used exception, but even then, is it so hard to type std::cout?
Always put curly braces around the clauses of your if statement, even if they are just one line. It's easy to forget to add braces if you need to add more statements to a clause later on, which can be quite confusing.
Your code formatting is pretty good, but pick a bracket style and be consistent. Either always put the opening curly brace on the same line as the function header / control statements etc, or always put it on the line afterwards.
Hope that helps.
I'm writing a code to index the skills available to a user in a game, constructed as a linked list. I've throughly tested the function that populates the list and it seems to be working correctly (so the head pointer for the list shouldn't be null). When I attempt to traverse the list to set values in the skill, before any of the code which writes to memory within the list gets to execute the program is crashing when I initialise the temp pointer within the search function of the list to the head pointer.
What makes this additionally weird to me is that it worked fine (and I had tested this fairly thuroughly) until I added in a list to store a list of available items, and may just be missing an odd interaction between the two when I populate them.
The specific error is that the pointer is supposedly accessing memory index 0x000000c to write to, but I don't see how the code at that point is dealing with a null pointer at all (since after 10 runs of the program the OS shouldn't be allocating that block of memory to the temp pointer every time and nothing else should be null.
I'm probably just ramblind at this point so here's the code:
The function that causes the error according to the debugger:
void Mechanics::setSkillValue(int index, int value)
{
Skill *temp = FirstSkill; // << The error is happening on this line //
while((temp != NULL)&&(temp->index != index))
{
temp = temp->next;
}
if (temp == NULL)
{
cout << "%";
}
else temp->setValue(value);
// cout << temp->returnValue(); //This was a test check, not needed for anything
}
The Function that's supposed to populate the skill and item lists.
void Mechanics::Populate()
{
ifstream skillstream("Skills.txt");
if(skillstream.is_open())
{
while(skillstream.good())
{
Skill *newskill;
int indexval;
string skillindex;
string skillname;
string skilldescription;
cout << "TP4" << endl; //TEST POINT
getline(skillstream, skillindex);
cout << skillindex;
getline(skillstream, skillname);
cout << skillname;
getline(skillstream, skilldescription);
cout << skilldescription; cout << endl;
indexval = atoi(skillindex.c_str());
newskill = new Skill(skillname, skilldescription,indexval);
//cout << "TP5" << endl; //TEST POINT
if(newskill == NULL) cout << "NULL!!!";
addSkill(newskill);
}
}
ifstream itemstream("Items.txt");
if(itemstream.is_open())
{
while(itemstream.good())
{
Item *newitem;
int indexval;
string skillindex;
string skillname;
string skilldescription;
string abilitydescription;
string valueSTR;
string typeSTR;
int value;
int type;
int numeric[5];
// cout << "TP4" << endl; //TEST POINT
getline(itemstream, skillindex);
// cout << skillindex;
getline(itemstream, skillname);
// cout << skillname;
getline(itemstream, skilldescription);
// cout << skilldescription;
getline(itemstream, abilitydescription);
getline(itemstream, valueSTR);
value = atoi(valueSTR.c_str());
getline(itemstream,typeSTR);
type = atoi(typeSTR.c_str());
for (int i=0; i < 5; i++)
{
string numericSTR;
getline(itemstream,numericSTR);
numeric[i]=atoi(numericSTR.c_str());
}
indexval = atoi(skillindex.c_str());
newitem = new Item(indexval, skilldescription, skillname, abilitydescription, value, type, numeric);
//cout << "TP5" << endl; //TEST POINT
// if(newskill == NULL) cout << "NULL!!!";
addItem(newitem);
}
}
The function that's supposed to actually add a skill to the skill list:
void Mechanics::addSkill(Skill *nskill)
{
Skill *temp = FirstSkill;
if(FirstSkill == NULL)
{
FirstSkill = nskill;
//cout << "TP1" << endl; //TEST POINT
//FirstSkill->printname();
}
else
{
while((temp->next != NULL))
{
temp = temp-> next;
//cout << "TP2" << endl; //TEST POINT
//temp->printname(); cout << endl;
}
if (FirstSkill != NULL)
{
temp->next = nskill;
nskill->next = NULL;
}
}
}
The code that I have is somewhat extensive so I'm only going to include the blocks which are potentially interacting with the function that's throwing up the error.
Thanks in advance for reading through this, and any assistance you're able to offfer, I've been banging my head against this for about 6 hours now and I've lost the perspective to actually track this one down.
so I have been trying to get an old c++ binary search tree program of mine to work.It compiles and runs but I do not get the results I would expect. If I insert c,d,a,b in that order and try to remove c, my remove function skips the if conditionals that find in order successors. Why are those 2 else if conditionals skipped?
Also it is compiled using gcc.
Node::Node(string nodeItem,
int nodeLine){
item=nodeItem;
vector<int> tempVector;
tempVector.push_back(nodeLine);
lines=tempVector;
leftPtr = NULL;
rightPtr = NULL;
}
// recursive method for finding node containing the word
Node* BST::find(string data, Node *curr) {
if(curr==NULL) {
cout << data << " is not in the tree" << endl;
return curr;
}
if(curr->getItem().compare("theplaceholder")==0){
return curr;
}
string tempItem = curr->getItem();
//this if statement is if I am inserting a word that is already in the tree
// or if I am removing the word from the tree
if(data.compare(tempItem)==0){
return curr;
}
else if(data.compare(tempItem)<0){
return find(data,curr->getLeftPtr());
}
else{
return find(data, curr->getRightPtr());
}
}
void BST::insert(string data, int fromLine) {
Node *curr;
curr=find(data, root);
if(curr!=NULL && curr->getItem().compare("theplaceholder")==0){
curr->setData(data);
curr->addLines(fromLine);
}
if(curr==NULL){
// I want to point to a nonNull node.
// I am making a new node and having curr point to that instead of NULL
//then I set it to
curr=new Node(data, fromLine);
cout <<curr->getItem() << endl;
vector<int> foundLines=curr->getNodeLines();
//cout<< "The word " <<curr->getItem() << " can be found in lines ";
if(foundLines.empty())
cout << "foundLines is empty";
int size=foundLines.size();
for(int count=0; count<size; count++){
//cout << foundLines[count] << ", ";
}
}
if(curr->getItem()==data){
curr->addLines(fromLine);
}
}
// remove method I am trying to check for in order successors to swap with the deleted node.
void BST::remove(string data) {
Node *curr=root;
Node *temp=find(data, curr);
if(temp==NULL){
cout << " nothing to remove" << endl;
}
else if(temp->getRightPtr()!=NULL){
curr=temp->getRightPtr();
cout << curr->getItem() << endl;
while(curr->getLeftPtr()!=NULL){
curr=curr->getLeftPtr();
cout << curr->getItem() << endl;
}
temp->setData(curr->getItem());
temp->setLines(curr->getNodeLines());
delete curr;
curr=NULL;
}
else if(temp->getLeftPtr()!=NULL){
cout <<"if !temp->getLeftPtr" << endl;
curr=temp->getLeftPtr();
cout << curr->getItem() << endl;
while(curr->getRightPtr()!=NULL){
curr=curr->getRightPtr();
cout << curr->getItem() << endl;
}
temp->setData(curr->getItem());
temp->setLines(curr->getNodeLines());
delete curr;
curr=NULL;
}
else{
cout <<"else delete temp" << endl;
delete temp;
temp=NULL;
}
}
The reason this line
else if(temp->getRightPtr()!=NULL){
never succeeds is that you never set the right pointer on any node - getRightPtr can only return null. If you'd examined the state of your tree in the debugger after you'd built it or if you stepped through the insert function you'd probably have seen this. The problems are:
your find function doesn't return null if the node isn't in the tree, whereas your insert function expects it will
your insert function needs to locate the position in the tree where this node should be - either through fixing the find function or on its own, then create a new node AND add a reference to it from the parent node, on either the left or right side as appropriate
your insert function appears the line number to the first-inserted node twice: once when you overwrite the placeholder and once at the end of insert (rather than use a placeholder here I'd probably have initialised root to be null and instead set root = curr when you create the first node)
your remove function needs to do more work when promoting the highest node from the left-hand branch; it needs to
correctly clean up that node from it's previous parent - at the moment you delete the object but leave any dangling pointers alone
promote any children of that node before you move it to take its previous slot
i.e.
D C
/ \ / \
A E remove 'D' A E
\ => 'C' is highest on left \
C but need to move B to C B
/
B