I've seen the some solutions to this in this website but none of them solved my problem.
I'm implementing an n-children, unbalanced tree type and the add operation gives me an exception.
The code is as follows:
struct Node {
// Just to initialize the parent node to zero, default constructor
Node(Node *parent = 0) : m_parent(parent) {
}
Node *m_parent;
vector<Node *> m_children;
GameBoard m_currentBoard;
};
Where the error is happening:
Node *tempNode = 0;
// Going through each of them to create new nodes
for (unsigned int i = 0; i < availableBoards.size() ; i++) {
// Create a new node
tempNode = new Node;
tempNode->m_parent = curNode;
tempNode->m_currentBoard.setBoard(availableBoards[i]);
// This is the line when program crashes
curNode->m_children.push_back(tempNode);
}
I have also tried declaring the tempNode inside the loop but it didn't help either.
I've checked through the watch from Visual Studio, curNode isn't NULL nor the tempNode.
Why am I getting this error?
Thanks for your answers.
OK the problem was destroying the object that was running the second code segment even before calling it. It was something like follows:
class A{
int *getAsdf();
int *asdf;
}
int main() {
A *newObj = new A;
delete newObj;
newObj->getAsdf();
}
I don't have a single clue as to how a method is called from an object that was deleted before. Error happened inside a function like getAsdf and even the parameters were valid. Can some-one explain?
Related
I have a problem with the application crashing at the line of code where if(!head) is being referenced inside the function: insertNode(). head and tail are class members of type node*. It looks like, I am missing something in the way the class members: head, tail are initialized..
This is the runtime error: "Unhandled exception at 0x00245246 in SLinkedlist_array.exe: 0xC0000005: Access violation reading location 0x00000000."
slinkedlist.h:
typedef struct node
{
int value;
struct node* next;
} node;
class slinkedlist
{
public:
//ctor, dtor, insertNode(int, int), displayList()
private:
node* head, tail;
};
slinkedlist.cpp:
bool slinkedlist::insertNode(int value, int aftNodeVal)
{
int toinsertval = value;
int searchkey = aftNodeVal;
bool retval = false;
// If it's a new linked list
if(!head) // THIS IS WHERE THE APPLICATION CRASHES!
{
node* head = new node;
head->value = toinsertval;
head->next = NULL;
return true;
}
else //It's not a new list
{
while(head->next != NULL)
{
//some more code here...
}
}
return retval;
}
void slinkedlist::displayList()
{
while(!head)
{
do
{
cout << head->value << " " ;
head = head->next;
}
while(head->next != NULL);
}
//return void;
}
main.cpp:
int main()
{
slinkedlist *s1 = NULL;
s1->insertNode(4, -1);
s1->displayList();
while(1);
}`
The answer is simple: you have null-pointer dereference here:
slinkedlist *s1 = NULL;
s1->insertNode(4, -1);
s1->displayList();
That's what exactly the system tells to you: "Access violation reading location 0x00000000"
Solution can be like:
slinkedlist *s1 = new slinkedlist;
s1->insertNode(4, -1);
s1->displayList();
delete s1;
Or like this (why not to use just an object on the stack?):
slinkedlist s1;
s1.insertNode(4, -1);
s1.displayList();
Or more C++ way (if you NEED a pointer):
auto s1 = make_unique<slinkedlist>(); // s1 is a std::unique_ptr<slinkedlist>
s1->insertNode(4, -1);
s1->displayList();
slinkedlist *s1 = NULL;
defines a pointer to a slinkedlist and DOES initialize it Unfortunately it initializes it to NULL, a safe parking address where (usually) no object are allowed to exist. For the vast majority of CPUs (every CPU I've ever worked on) accessing this dead zone around NULL will crash the program, making it much easier to detect bugs.
There is no need for a pointer here. If you don't need pointer, don't use one. Your life will be much easier.
int main()
{
slinkedlist s1; // default initializes
s1.insertNode(4, -1);
s1.displayList();
while(1); // rethink this. If you want to hold a program open to see the output
// while debugging, place a breakpoint in the debugger.
}
Default initializing of s1 alone will not help you because it will do the absolute minimum work to initialize its member variables, and in the case of a pointer the minimum work is to do nothing and leave head and tail uninitialized and pointing (sort of. tail is NOT a pointer) to an indeterminate location. Because you aren't also asking about the compiler error you should get from assigning NULL to tail, the program is clearly not initializing tail and I'll assume the slinkedlist constructor doesn't do much.
Side note: If you have a constructor or destructor that don't do anything (and don't need to do anything) leave them out and let the compiler generate the appropriate code. Code that does not exist (and doesn't need to exist) has no bugs.
class slinkedlist
{
public:
//ctor, dtor, insertNode(int, int), displayList()
private:
node* head, tail; // the * only applies to head.
};
could be
class slinkedlist
{
public:
//ctor, dtor, insertNode(int, int), displayList()
private:
node* head = nullptr;
node* tail = nullptr;
};
if you are compiling to recent (2011 or newer) C++ Standards. You won't need a constructor, the work is done for you with the default assignments. You will still need a destructor along with a copy constructor and an assignment operator to satisfy The Rule of Three.
In older C++ Standards you need to make the constructor smarter
class slinkedlist
{
public:
slinkedlist(): head(NULL), tail(NULL)
{
}
//dtor, insertNode(int, int), displayList()
private:
node* head; // I recommend splitting the definitions up. It makes the code easier
// to read and makes it harder to make mistakes.
node* tail;
};
You will still need a destructor, a copy constructor, and an assignment operator.
Note that this also applies to node. If you dynamically allocate a node and do not explicitly set next to a value, you won't know where next points, and all of the tests like
while(head->next != NULL)
will fail horribly.
I'm trying to learn how to use the gdb debugger to fix this sample code. When stepping through the debugger, I can see that the line 'mylist[i]->val = i;' is throwing the segmentation fault.
I think I understand what a segmentation fault is, but I don't understand how this line could be causing it. Do I need to allocate memory for the mylist vector? How would I do that? I thought that the vector was already initialized and ready in main(), but I'm not really sure.
I have tried using 'new' for each node in the mylist vector but that gave me a compile error.
node* mylist[i] = new node; //what I tried
mylist[i]->val = i;
mylist[i]->next = NULL;
//error message
error: array must be initialized with a brace-enclosed initializer
node* mylist[i] = new node;
My code
class node
{
public:
int val;
node* next;
};
void create_LL(vector<node*>& mylist, int node_num)
{
mylist.assign(node_num, NULL);
//create a set of nodes
for (int i = 0; i < node_num; i++)
{
mylist[i]->val = i; //error happens here
mylist[i]->next = NULL;
}
... (relevant section of main() below)
int main(int argc, char ** argv)
{
const int NODE_NUM = 3;
vector<node*> mylist;
create_LL(mylist, NODE_NUM);
The actual error shown is "Segmentation fault (core dumped)"
When I print mylist right before the error line it shows
$1 = std::vector of length 3, capacity 3 = {0x0, 0x0, 0x0}
I am still learning c++ so I might be missing something really basic.
I would really appreciate any help. Thanks!
For starters, it's better if you hide variables inside a class. If you're not going to, the convention is to use a struct. It's also good practice to provide some constructor in that case, and maybe with default values:
class node
{
int val;
node* next;
public:
node(int v= 0, node* n= nullptr) : val(v), next(n) {}
};
Note the use of nullptr instead of NULL. Using the latter is a bad practice in c++.
The problem is that you can't use positions on a std::vector if they have not been allocated. When you do mylist[i]->val = i; you're in the lands of undefined behaviour.
You need first to push_back() or emplace_back() into a std::vector. So it's size() grows as it puts your data at the end (the back) of the vector. You could also use other methods, like reserve(). While push_back() pushes node* elements on your list, emplace_back() would construct them in place with no copy (no difference with raw pointers, but you can use a vector<node> instead of vector<node*> which is more straightforward.
// create a set of nodes
void create_LL(vector<node>& mylist, int node_num)
{
for (int i = 0; i < node_num; i++) {
mylist.emplace_back(i, nullptr); // calls node::node(i, nullptr) and inserts it at the end of the vector
}
or
// create a set of nodes
void create_LL(vector<node*>& mylist, int node_num)
{
for (int i = 0; i < node_num; i++) {
mylist.emplace_back(new node(i, nullptr));
}
I am learning list in C++ independently, and i have searched many websites about it. However, almost every approach to create a list is the same.
They usually create a struct as the node of a class. I want to create a class without using struct. So I created a class name ListNode which contains an int data and a pointer.
The main member functions of my class are AddNode and show.
Although, this program compiles successfully, it still does not work as I wish.
Here is the header file:
#ifndef LISTNODE_H_
#define LISTNODE_H_
#pragma once
class ListNode
{
private:
int data;
ListNode * next;
public:
ListNode();
ListNode(int value);
~ListNode();
void AddNode(ListNode* node,ListNode* headNode);
void show(ListNode* headNode);
};
#endif
Here is the implementation:
#include "ListNode.h"
#include<iostream>
ListNode::ListNode()
{
data = 0;
next = NULL;
}
ListNode::ListNode(int value)
{
data = value;
next = NULL;
}
ListNode::~ListNode()
{
}
void ListNode::AddNode(ListNode* node,ListNode* headNode) {
node->next = headNode;
headNode =node;
}
void ListNode::show(ListNode* headNode) {
ListNode * traversNode;
traversNode = headNode;
while (traversNode != NULL) {
std::cout << traversNode->data << std::endl;
traversNode = traversNode->next;
}
}
Main function:
#include"ListNode.h"
#include<iostream>
int main()
{
using std::cout;
using std::endl;
ListNode* head = new ListNode();
for (int i = 0;i < 3;i++) {
ListNode* Node = new ListNode(i);
head->AddNode(Node, head);
}
head->show(head);
return 0;
}
As far as I am concerned, the output should be
2
1
0
However, the output is a single zero. There must be something wrong in the AddNode and show function.
Could you please tell me what is wrong with these two functions?
When you call head->AddNode(node, head) you´re passing the memory directions which the pointers point, when the function arguments receive those directions, they are now pointing to the same directions, but those are another pointers, no the ones you declared in main. You could see it like this:
void ListNode::AddNode(ListNode* node,ListNode* headNode) {
/*when the arguments get their value it could be seen as something like:
node = Node(the one from main)
headNode = head(the one from main)*/
node->next = headNode;
/*Here you are modifying the new inserted node, no problem*/
headNode = node;
/*The problem is here, you´re modifying the memory direction
headNode points to, but the headNode argument of the function, no the one declared in main*/
}
So the pointer head in main() always points to the same first node you also declared in main().
In order to fix this you should change your code this way:
void ListNode::AddNode(ListNode* node,ListNode** headNode) {
/* second paramater now receives a pointer to apointer to a node */
node->next = *headNode;//the same as before but due to pointer syntaxis changes a bit
*headNode = node;//now you change the real head
}
And when you call it:
head->AddNode(Node, &head);//you use '&' before head
Now the real head, no the one in the function, will point to the last node you inserted.
I have created a linked list class VW with a function Build to add nodes to the list. However, when I run the code to build my linked list, the Build function throws an "access violation" error. The error is thrown by the call tmp->NextObj() in the Build function.
If the object of class VW is newly created and the Build is called for the first time, then the condition if(tmp==NULL) in the Build function should be true, and hence the program should not enter the else section during the first call to Build. What am I missing here? Could you please help.
class VW
{
World_Obj *head;
public:
void Build(...);
};
void VW::Build(...)
{
World_Obj *newObj;
newObj = new World_Obj;
newObj->SetData(...);
newObj->SetNext(NULL);
World_Obj *tmp;
tmp = this->head;
if (tmp == NULL)
this->head = newObj;
else
{
while (tmp->NextObj() != NULL)
{
tmp = tmp->NextObj();
}
tmp->SetNext(newObj);
}
}
int main()
{
VW *g_w;
g_w = new VW;
/* Reading arguments from input file*/
g_w->Build(...);
}
The issue was the missing constructor in the class VW,
VW(){ head=NULL;}
Thanks all!
Here is a big problem:
tmp = this->head;
...
while (tmp->NextObj() != NULL)
{
tmp = tmp->NextObj();
}
tmp->SetNext(newObj);
...
delete tmp;
When the loop ends and after you do tmp->SetNext(newObj) then tmp will point to the second to last node in the list. Which you then promptly destroy by deleting it.
That means your list will now somewhere contain a node that no longer exist, and attempting to dereference it will lead to undefined behavior and most likely a crash.
The solution is simply to not delete tmp.
I am in process of learning c++. I am working on creating a linkedlist data structure. One of the functions that displays the values of nodes in the structure does not work. For some reason the while loop that traverses through nodes doesn't work in the display function, hence I can't see the values in those nodes. Does anyone see what the problem is? I've been staring at the code for a while and not sure what is wrong here.
Thanks for your help in advance.
Header:
// linklist.h
// class definitions
#ifndef LINKLIST_H
#define LINKLIST_H
class linklist
{
private:
// structure containing a data part and link part
struct node
{
int data;
node *link;
}*p;
public:
linklist();
void append(int num);
void addatbeg(int num);
void addafter(int loc, int num);
void display();
int count();
void del(int num);
~linklist();
};
#endif
.cpp file
// LinkedListLecture.cpp
// Class LinkedList implementation
#include"linklist.h"
#include<iostream>
using namespace std;
// initializes data member
linklist::linklist()
{
p =NULL;
}
// adds a node at the end of a linked list
void linklist::append(int num)
{
node *temp, *r;
// if the list is empty, create first node
if(p==NULL)
{
temp = new node;
temp->data = num;
temp->link = NULL;
}
else
{
// go to last node
temp = p;
while(temp->link!=NULL)
temp = temp->link;
// add node at the end
r = new node;
r->data=num;
r->link=NULL;
temp->link=r;
}
}
// displays the contents of the linked list
void linklist::display()
{
node *temp = p;
cout<< endl;
// traverse the entire linked list
while(temp!=NULL) // DEBUG: the loop doesn't work
{
cout<<temp->data<<" ";
temp = temp->link;
}
void main()
{
linklist l;
l.append(14);
l.append(30);
l.append(25);
l.append(42);
l.append(17);
cout<<"Elements in the linked list:";
l.display(); // this function doesn't work
system("PAUSE");
}
You never set p to a non NULL value.
if(p==NULL)
{
p = new node;
p->data = num;
p->link = NULL;
}
I think GWW has highlighted the issue, but part of learning to program it to learn how to identify the mistakes.
If you do something and don't get the expected result you could:
Use the visual c++ debugger to step through and see the values of your variables.
Put in log lines to report information you think is important
inspect the code - if you think something is right but it doesn't work, then go to an earlier step and check it does the right thing.
Add unit tests, or follow design by contract adding pre/post conditions and class invariants.
Learning to program C++ by writing a linked list is like learning math by adding 1 + 1. It is old fashioned thinking, slow and mostly boring without having any context.
Math isn't calculating, like C++ programming isn't pointer manipulation. At some stage you might need to know about it, but your better off learning other important things like stl and boost.
If it was understood that append() ment create something, find the end of the list, add it. you could then see that in you append function you have create something mixed uyp with move to the end of the list, but you never add it.