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.
Related
I have started learning c++ (coming from java background) and barely reached pointers and got stuck. When I debug this program it says, program received segmentation fault (SIGSEGV signal) at line
*previous = head;
in the following code.
#include <iostream>
using namespace std;
struct Node
{
int data;
Node *link;
};
int main()
{
cout << "Starting main program \n";
Node head;
head.data = 0;
head.link = NULL;
cout << "After declaring head and initializing values \n";
//Declaring a pointer variable which points to an entity of type struct.
Node *previous;
*previous=head;
cout << "After declaring previous pointer \n";
bool done = false;
int i = 1;
cout << "First while loop\n";
while(!done)
{
cout << i << ": Iteration";
Node temp;
temp.data=i;
temp.link=NULL;
if(i > 2)
{
done = true;
continue;
}
*previous->link=temp;
++i;
*previous = temp;
}
done = false;
cout << "Declaring temp pointer before printing \n";
Node *temp;
*temp = head;
cout << "Second while loop\n";
while (!done)
{
cout << i << ": Iteration";
if(temp == NULL)
{
done = true;
continue;
}
cout << temp->data << "->";
*temp = *temp->link;
}
cout << "NULL";
}
Why is the pointer initialization incorrect ?
First problem:
Node *previous;
*previous=head;
First line declares that previous will hold the address of a Node. It is not initialized, so whatever value happens to be on the stack will be picked up as the bit pattern it holds.
Unfortunately, the 2nd line then dereferences the pointer (which points to garbage) and attempts to copy head into random memory (hence your crash).
In this case you probably want previous to point to head, which is taking head's address and assigning it:
Node* previous = &head; // initialize at the point of declaration
However, you must also be very wary of pointers to variables declared on the stack, because the addresses will soon become invalid when the function returns or the scope exits.
(Usually data structures with pointers are using values allocated on the heap, so the objects outlive the function that declares them.)
Which brings us to the second problem:
while(!done)
{
cout << i << ": Iteration";
Node temp;
Already there's a problem. temp is declared inside the loop on the stack. Each loop iteration, the variable will automatically be destroyed. Therefore it cannot participate in your linked list without corrupting it.
You want your list nodes to be created with new, and when you update previous's next pointer, you want to assign an address TO it, not copy an object THROUGH it.
Something like this:
while(!done)
{
cout << i << ": Iteration";
Node * temp = new Node();
temp->data = i;
temp->link = nullptr; // better than NULL
if(i > 2)
{
break;
}
previous->link = temp;
++i;
previous = temp;
}
The head object should probably also be heap allocated. Of course, now you have to deal with cleaning up the memory by calling delete on all the nodes.
There were some bugs in the code but major ones were :-
you were not allocating memory for the new nodes that you were adding during runtime
you were creating instances of structure but instead you were required to create an pointer pointing to the structure ( instances will be created during runtime ( using new operator )
I have added the comments to the code explaining what exactly are the changes that I have done.
Here is the fix :-
#include <iostream>
using namespace std;
struct Node
{
int data;
Node *link;
};
int main()
{
cout << "Starting main program \n";
// Allocating memory for the new instance of Node and making "head" pointing to it
Node *head = new Node;
head->data = 0;
head->link = NULL;
cout << "After declaring head and initializing values \n";
//Declaring a pointer variable which points to an entity of type struct.
Node *previous;
// As head and previous both are pointers thus can be assigned as it is
previous = head;
cout << "After declaring previous pointer \n";
bool done = false;
int i = 1;
cout << "First while loop\n";
while(!done)
{
cout << i << ": Iteration";
// Allocating memory for the new instance of Node and making temp pointing to it
Node *temp = new Node;
// As temp is a pointer thus using member access ("- >") operator to access the members
temp->data=i;
temp->link=NULL;
if(i > 2)
{
done = true;
continue;
}
previous->link = temp;
++i;
previous = temp;
}
done = false;
cout << "Declaring temp pointer before printing \n";
Node *temp;
temp = head;
cout << "Second while loop\n";
while (!done)
{
cout << i << ": Iteration";
if(temp == NULL)
{
done = true;
continue;
}
cout << temp->data << "->";
temp = temp->link;
}
cout << "NULL";
}
My program is a list of cities, it's good but when I call to popFront(), I don't know why but it doesn't work, then I call any function and the program is over.
City* popFront(Nodo*& header, Nodo*& trailer) {
City* libras;
if (inicio) {
strcpy(libras->Name,inicio->dato.Name );
libras->Num = header->dato.Num;
Nodo* aux = header;
header= header->next;
header->previous= NULL;
delete aux;
if (!header) trailer = NULL;
}
return libras;
}
void read(Nodo*& head) {
Nodo* aux = head;
int pos = 1;
while (pos <= node_count) {
cout << "pos" << pos << endl;
cout << "Name> " << aux->dato.Name << endl;
cout << "NUm> " << aux->dato.Num << endl;
aux = aux->next;
pos++;
}
if (node_count == 0)cout << "Empty list" << endl;
}
Well, I'm not sure this is the only problem, but this right here is wrong:
City* libras;
You need to allocate it before you use it, like this:
City* libras = new City;
Otherwise, something like strcpy(libras->Name,inicio->dato.Name ); will fall and crash hard. That's because it's UB (Undefined Behavior) to access a pointer to memory that is unallocated.
Of course, you will need to delete it when you're done with it, but you seem to know and understand that already based on your other code:
delete libras; // Or wherever the returned pointer gets stored
This may be a dumb question but I'm getting pretty desperate at this point.
I am attempting to create an array of pointers:
struct vertex
{
std::string id;
std::string name;
int networkID;
std::vector<adjVertex> friends;
bool visited;
};
struct hobbylist
{
std::string hobby;
std::vector<vertex*> list;
};
hobbylist * hobbies[HASHMAP_SIZE];
int Graph::addUserToHobby(std::string hobby1, std::string id){
//cout << "Adding to hobby: " << hobby1 << " user: " << id << endl;
vertex *user = findVertex(id);
int collisions = 0;
// initial key is based on the first 2 characters of the hobby name
int key = (hobby1[0] + hobby1[1]) % HASHMAP_SIZE;
//cout << " initial hashmap key " << key << endl;
hobbylist *h = new hobbylist;
if(hobbies[key] == NULL){
h->hobby = hobby1;
h->list.push_back(user);
hobbies[key] = h;}
else if (hobbies[key]!=NULL){
hobbies[key]->list.push_back(user);
collisions++;}
return collisions;
}
I am getting a seg fault at the last line in the else statement in the addUserToHobby function when running the function the first time and I am confused why the function would go to the else statement when the array should be empty and therefore hobbies[key] should be null the first time the function is run? Upon further inspection the function will always enter the else statement, so the array values are never null?
Each location is the array is not set to null by default, it's just whatever trash was in there before you allocated it.
Here is some code that I have made that should copy all the nodes in a linked data type correctly, but it is not working. I have checked my logic and wrote it on paper many times, yet it still isn't working. Am I doing something wrong on this part of the code? Is my use of pointers to copy nodes accurate? The part of my Constructor test that goes haywire is the part that starts to print out what's in the queue.
void LinkedQueue<ItemType>::CopyNodesFrom(const LinkedQueue& a_queue)
{
Node<ItemType>* orig_chain_ptr = a_queue.front_ptr_; // Points to nodes in original chain
if (orig_chain_ptr == nullptr) {
front_ptr_ = nullptr; // Original queue is empty
back_ptr_ = nullptr;
return;
}
// Copy first node
front_ptr_ = new Node<ItemType>();
front_ptr_->SetItem(orig_chain_ptr->GetItem());
// Advance original-chain pointer
orig_chain_ptr = orig_chain_ptr->GetNext();
// Copy remaining nodes
Node<ItemType>* new_chain_ptr = front_ptr_; // Points to last node in new chain
Node<ItemType>* temp_ptr;
while (orig_chain_ptr != nullptr) {
temp_ptr = new Node<ItemType>(orig_chain_ptr->GetItem() );
new_chain_ptr->SetNext(temp_ptr);
orig_chain_ptr = orig_chain_ptr->GetNext(); //Advance Our original pointer
new_chain_ptr = new_chain_ptr->GetNext(); //Advance our new chain pointer
} // end while
new_chain_ptr->SetNext(nullptr);
back_ptr_ = new_chain_ptr;
} // end copy constructor
#include <iostream>
#include <string>
#include "LinkedQueue.h" // ADT Queue operations
using namespace std;
void CopyConstructorAndAssignmentTester() {
LinkedQueue<string> queue;
string items[] = {"zero", "one", "two", "three", "four", "five"};
for (int i = 0; i < 6; i++) {
cout << "Adding " << items[i] << endl;
bool success = queue.Enqueue(items[i]);
if (!success)
cout << "Failed to add " << items[i] << " to the queue." << endl;
}
cout << "Queue contains, from front to back, zero one two three four five." << endl;
cout << "Checking Copy Constructor tester " << endl;
LinkedQueue<string> copy_of_queue(queue);
cout << "Copy of queue contains, from front to back, ";
for (int i = 0; i < 6; i++)
{
cout << " " << copy_of_queue.PeekFront();
copy_of_queue.Dequeue();
}
cout << "." << endl;
/*
cout << "Checking Assignment Operator tester " << endl;
LinkedQueue<string> assigned_queue;
assigned_queue.Enqueue("ha");
assigned_queue.Enqueue("ba");
assigned_queue = queue;
cout << assigned_queue << endl;*/
/* cout << "Assigned queue contains, from front to back, ";
for (int i = 0; i < 6; i++)
{
cout << " " << assigned_queue.PeekFront();
assigned_queue.Dequeue();
}
cout << "." << endl;
cout << "Original queue contains, from front to back,";
for (int i = 0; i < 6; i++) {
cout << " " << queue.PeekFront();
queue.Dequeue();
}
cout << "." << endl << endl; */
} // end copyConstructorTester
int main()
{
CopyConstructorAndAssignmentTester();
char a;
cin >> a;
//ConcatenateTester();
//return 0;
} // end main
EDIT: Oh crap, this stumps more people than I thought. XD. I thought I made a blatantly obvious mistake.
This may not be the answer you are looking for, and I'm finding it difficult to spot mistakes in your code lacking the full information of the states being manipulated.
The linked list logic looks all right: nothing jumps out at me as being faulty there in terms of the logic used to copy. Put in a distilled form:
first_node = last_node = new Node(other.first_node->data);
for (Node* other_node = other.first_node->next; other_node; other_node = other_node->next)
{
Node* new_node = new Node(other_node->data);
last_node->next = new_node;
last_node = new_node;
}
last_node->next = nullptr;
I believe this is what you have and it should be correct in terms of the overall logic. Any problems will probably be found elsewhere. Nevertheless, it should make your life easier to reduce the number of states you're working with. This 'new_chain_ptr' is unnecessary and you can just write out the results to 'back_ptr_' directly.
However, I have a different suggestion. You have the rest of the Queue working correctly, yes, including these methods like 'Enqueue'? If so, your copy constructor can be more trivially implemented just using what works already. Start with the state for an empty queue, and then read the elements from the other queue and 'Enqueue' those elements into your copy. Now you can avoid getting yourself tangled up in the low-level linked list logic by utilizing the parts you already know are functioning like so:
// Create empty queue.
first_node = last_node = nullptr;
// Enqueue elements from other queue.
for (Node* other_node = other.first_node; other_node; other_node = other_node->next)
Enqueue(other_node->data);
It might cost you an additional branch or so per iteration but remember that correctness always precedes efficiency, and you can come back and optimize once you have it working. Remember to handle self-assignment if the logic cannot work properly in those cases.
And yes, a debugger will give you a massive edge in accelerating the understanding of the nature of your code in addition to spotting mistakes more quickly.
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]