read access violation error - c++

class Node{
private:
string name;
Node** adjacent;
int adjNum;
public:
Node();
Node(string, int adj_num);
Node(const Node &);
bool addAdjacent(const Node &);
Node** getAdjacents();
string getName();
~Node();
};
bool Node::addAdjacent(const Node &anode){
Node** temp;
temp= new Node*[adjNum+1];
for(int i=0;i<adjNum+1;i++)
temp[i]=adjacent[i];
temp[adjNum]=const_cast<Node *>(&anode);
delete[] adjacent;
adjacent=new Node*[adjNum+1];
adjacent=temp;
delete[] temp;
adjNum++;
return true;
}
int main()
{
Node node1("A",0);
Node node2("B",0);
node1.getName();
node1.addAdjacent(node2);
system("PAUSE");
return 0;
}
when the program comes to this part:
for(int i=0;i<adjNum+1;i++)
temp[i]=adjacent[i];
it says Access violation reading location 0xcccccccc. The class must allocate the memory fore adjacent, but I think it didn't how can I solve this problem?

adjacent=new Node*[adjNum+1];
adjacent=temp;
delete[] temp;
This looks like a bug. You probably meant to write:
adjacent = temp;
and that's it.
Also, I think the problem lies with
for(int i=0;i<adjNum+1;i++)
You're copying adjNum+1 elements, even though (I assume) adjacent only contains adjNum elements. Remove the +1 from the for loop.

Besides the issues strager mentioned, you might be missing initialization for adjacent, e.g. like this:
Node::Node(std::string name, unsigned adj_num)
: name(name)
, adjacent((adj_num > 0) ? new Node*[adj_num] : 0)
, adjNum(adj_num)
{}
Note the unsigned parameter, a negative adj_num is most likely meaningless in this context.
If you don't initialize adjacent, it contains some garbage value and dereferencing it or passing it to delete[] leads to undefined behaviour.

Related

How to fix 'Segmentation fault' error in c++

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));
}

Segmentation Fault (core dumped) linked list

Hey guys I'm trying to run this code but I get segmentation fault when the compiler gets to the class functions.
This is the main function:
int main (int argc, char* argv[]){
cout<<"\t1.Add Program\n";
cout<<"\t2.Kill Program\n";
cout<<"\t3.Fragmentation\n";
cout<<"\t4.Print Memory\n";
cout<<"\t5.Exit"<<endl;
LinkedList Memory;
Memory.createMemory(); (I get the segmentation error on this line)
int choice;
cin>>choice;
cout<<"choice - "<<choice<<endl;
if (choice==1){
string programName;
cin>>programName;
cout<<"Program name - "<<programName<<endl;
int size;
cin>>size;
cout<<"Program size (KB) - "<<size<<endl;
int numpages;
if (size%4==0) numpages=size/4;
if (size%4!=0) numpages=size/4+1;
Memory.addProgram(numpages, programName);
return 0;
}
This is the class
class LinkedList{
private:
struct node{
string name;
node *next;
};
public:
void createMemory();
void addProgram(int val, string s);
void killProgram(string s1);
void print();
void fragmentation();
LinkedList(){head=NULL;};
};
And these are two of the class functions
void LinkedList::createMemory(){
int i=0;
node* temp;
temp = new node;
while(i<32){
temp->name="Free";
temp=temp->next;
i++;
}
};
void LinkedList::addProgram(int val, string s){
int i=0;
node* temp;
temp=new node;
while(temp->name!="Free")
temp=temp->next;
while(temp->name=="Free"){
while (i<val){
temp->name=s;
temp=temp->next;
i++;
}
}
cout<<"Program "<<s<<" added successfully: "<<val<<" page(s) used."<<endl;
};
The other functions in the class are similar to these two so they're all gonna have the same error.
The main function runs correctly, but when I call the class functions in the main i get the segmentation fault.
while(i<32){
temp->name="Free";
temp=temp->next;
i++;
}
In this snippet, you use null or uninitialized temp->next
Maybe there are more subtle errors in your code. Use a debugger.
Tip always to keep in keep in mind: in constructor initialize all members, not only selected.
In my code, I use constructors for struct too (some people advice otherwise)
In LinkedList::createMemory and LinkedList::addProgram, you are creating a new node in the scope of the function but you are not assigning such new node to a class variable. Therefore, when you exit your function, the pointer to the resource you created is lost and:
1) you leaked memory because you haven't called delete on the pointer
2) your class doesn't have any nodes
add a
node *_root;
variable to your LinkedList class and assign to it.
Now with this being said here's a couple of tips:
Don't use new like that, it is very easy to leak memory. Use std::unique_ptr so that resources are automatically cleared.
Use std::list if you want to have a LinkedList.
'createMemory()' Method that initializes the List got problem with memory allocation. Only the first node got memory allocated. You are re-assigning 'temp' with 'temp->next' which does not have memory allocated to it and accessing 'temp->name' which would cause the 'Segmentation fault'. If you are creating multiple nodes in an iterative fashion, you must allocate memory for each of the nodes in the loop. Use this stanford link as a reference to learn how to initialize Linked List: http://cslibrary.stanford.edu/103/LinkedListBasics.pdf

C++ object pointer scope

I started writing a binary tree and then came up with this example and I'm not sure what's going on. So here's the code:
#include<iostream>
using namespace std;
struct Node
{
Node *left, *right;
int key;
Node()
{
left = NULL;
right = NULL;
key = 0;
}
Node(int key)
{
left = NULL;
right = NULL;
key = key;
}
};
struct Tree
{
Node* root;
void Add(int k)
{
Node* t;
t->key = k;
root->left = t;
}
Tree(int key)
{
this->root = new Node(key);
}
};
int main()
{
Tree* tree = new Tree(5);
tree->Add(4);
cout<<tree->root->left->key;
return 0;
}
Add function Add in Tree is whats confuses me. So, there is a pointer to Node object, but new keyword is not used and it appears to me that anyway there is memory allocated in the heap because I can reach the object. Shouldn't go out of scope and be destroyed? And why I can reach that object and print out its key?
Probably that memory belongs to your program and nothing bad seems to happen because you are using so little memory. If you use more memory, some object will own that unallocated space and expect it to remain unmodified. Then this code will start giving you problems.
You are "dereferencing an uninitilized pointer". There are questions relating to this here and here, for instance. Your compiler may blow up if you do this, or it may not: the behaviour is undefined. Anything might happen, including the appearance that things are working.
Use new, like you should.
This line …
Node* t;
… is like:
Node* t = random_address;
It means that the next line …
t->key = k;
… is able to corrupt interesting memory locations.
The code is invalid. In this function
void Add(int k)
{
Node* t;
t->key = k;
root->left = t;
}
local variable t is not initialized and has indeterminate value. So the execution of the statement
t->key = k;
results in undefined behaviour.
You correctly pointed to that there must be used operator new. For example
Node* t = new Node( k );
Nevertheless even in this case the function is invalid because it has to check whether the new key is less of greater than the key of root. Depending on the condition there should be either
root->left = t;
or
root->right = t;

Why does this binary search tree cause a stack overflow?

#include<iostream>
using namespace std;
/*main idea is to construct ordered statistic tree,which is similar of
binary search tree,width addition of one key,which shows us it's rank in given
tree,for this i introduced additional one key-rank
*/
struct node
{
int val;
node *left,*right;
int rank;
node(int t) { val=t;left=right=NULL;}
};
node *root;
void insert(node *p,int ele)
{
if(p==NULL){
p=new node(ele);
return ;
}
else if(ele<p->val)
{
insert(p->left,ele);
}
else if(ele>p->val)
{
insert(p->right,ele);
}
}
void inorder (node *p)
{
if(p!=NULL){ inorder(p->left);
cout<<p->val<<" "<<p->rank;
inorder(p->right);
}
}
int count_node(node *t)
{
int sum=0;
if(t==NULL) return 0;
else sum=1;
if(t->left) sum+=count_node(t->left);
if(t->right) sum+=count_node(t->right);
return sum;
}
int main()
{
root=NULL;
root->rank=0;
insert(root,26);
insert(root,17);
insert(root,41);
insert(root,14);
insert(root,30);
insert(root,21);
insert(root,47);
insert(root,10);
insert(root,16);
insert(root,28);
insert(root,38);
insert(root,35);
insert(root,39);
insert(root,19);
insert(root,21);
insert(root,20);
insert(root,7);
insert(root,12);
insert(root,3);
inorder(root);
return 0;
}
This code causes an overflow, but I do not understand why, because I have constructed the constructor properly.
The problem is:
root=NULL;
root->rank=0;
this cause undefined behavior because you dereference a NULL pointer. Anything can happen.
Also:
void insert(node *p,int ele)
{
if(p==NULL){
p=new node(ele);
return ;
}
//...
}
This doesn't modify the original pointer. If you call insert on a NULL pointer, it will be NULL when the function returns. You need to pass it by reference:
void insert(node *& p,int ele)
In addition to what Luchian said, you also have this problem:
void insert(node *p,int ele)
{
if(p==NULL){
p=new node(ele);
return ;
}
....
where the pointer p is passed by value. When you say p=... you are changing a copy of the pointer that is only visible to the function. You might want a reference to the pointer you're changing:
void insert(node *&p, int ele){ ... }
You have a very big issue the first two lines of your main function:
root=NULL;
root->rank=0;
If you look at your own definition above, the root is defined as a node pointer, that is it does not reserve any space for an actual node.
If you do not reserve the space yourself, than you are trying to write through uninitialized memory. What's more, you explicitly say that the root points to nothing, that is NULL. And in the very next line, you try to access it's member called rank.
You should try replacing the line:
root = NULL;
With
root = new node(0);
or something similar that actually reserves the space and constructs a node.
Alternatively, you could try assinging the rank to the root in the very end, since you insert function actually constructs the root if it is not present. edit as Luchian said, you only try to construct the root in the insert method. If you re-write the insert method in the way he has suggested, than it might all work if you just move the root->rank=0; line to the end of the insertion process.
root=NULL;
root->rank=0;
This could be the problem, you should not deference a NULL object.

Breadth First Search on a Binary tree

I'm trying to traverse on a binary tree to find someone's ID by using his/her ID number. When I debug this function it works well, but on the other hand, when I directly run, it terminates itself.. Can someone figure it out please?
struct person{
char ID[15];
char name[30] ;
char surname[30];
person *left;
person *right;
};
struct tree{
person *root;
void bfsSearch();
void BFS(person*,char*);
};
void tree::BFS(person *root,char *search)
//BFS traversal on a binary tree
{
char *temp;
std::deque<person *> q;
q.push_back(root);
temp=strncpy(temp,q.front()->ID,8);
while (q.size() != 0)
{
person *next = q.front();
if (strcmp(search,temp)==0)
{
cout<<"Result: "<<q.front()->ID<<endl;
break;
}
q.pop_front();
if (next->left)
q.push_back(next->sol);
if (next->right)
q.push_back(next->sag);
temp=strncpy(temp,q.front()->ID,8);
}
}
void tree::bfsSearch()
{
person *scan;
char *data,*temp;
data=new char[15];
scan=root;
cout<<"Enter the Person`s ID to search: ";cin>>data;
BFS(root,data);
}
char *temp;
temp=strncpy(temp,q.front()->ID,8);
You are copying data into an uninitialized pointer, which is undefined behavior. You need to declare temp as an array, or allocate it dynamically. Since you are only copying up to 8 bytes, using char temp[9]; should be enough. Note though that strncpy will leave the string unterminated if the input was too long, so you'd need to add temp[8]=0; to be safe.
There is also no point in assigning the result of strncpy back to temp, since it just returns its first argument.
It's much better to do things the C++ way: Use std::string and avoid all this messing around with char pointers and null-terminators.