I am trying to write a code for a linked list but when I try to add a node the code gets stuck at the line immediately after the while loop in the add() function, reporting an access violation error. What's wrong?
#include<iostream>
template <class T>
class linkedlist
{
struct node
{
T data;
node *lp;
}*p;
public:
linkedlist();
void add(T t);
};
template<class T>
void linkedlist<T>::add(T t)
{
node *r,*q;
r = q = p;
while(p!= NULL)
{
q = p;
p = p->lp;
}
q->lp = new node;
q->lp->data = t;
p = r;
}
template<class T>
linkedlist<T>::linkedlist()
{
p = NULL;
}
int main()
{
linkedlist<int> l1;
l1.add(3);
}
You initialize p to NULL in the constructor, then try to dereference it in add (via q):
r = q = p;
// the while loop will not be executed as p == NULL
q->lp = new node;
You must initialize p first - either during construction (in which case your "empty" list won't be physically empty, so you must deal with this specifically, e.g. when iterating / removing elements), or you should check in add for the case when p == null and handle it differently.
Side note: p is supposed to point to your head element, so it is risky to use it also to iterate through the list in add, then restore its original value (stored in r). Why not simply leave it always intact, and use r for iterating? One less chance for bugs.
You should initialize the node in the constructor:
p = new Node;
Because here:
while(p!= NULL)
{
q = p;
p = p->lp;
}
q->lp = new node;
p is initially NULL, so q will also be NULL, ergo q->lp leads to undefined behavior and a crash.
Either initialize p or re-think your logic.
Related
I get EXC_BAD_ACCESS (code=1, address=0x0) on the 3rd last line where I return a *Bitvector. As you can see in the main I try to flip the 10'th index to 1. I highly suspect the way I manage my memory is the cause, but can't figure out where and how. (Note that the BinTree is not completed, I'm using a mac, and I use vs-code).
struct node {
BitVector b;
node* parent;
node* right;
node* left;
};
class BinTree {
node* root;
node* insert(node* t, int g) {
if (t==NULL) {
t->b.get_bitvector()->at(g) = 1; //Here I try to set the g'th index to be 1 in the bitvector.
}
return t;
}
public:
BinTree() {
root = NULL;
}
void insert(int g) {
root = insert(root, g);
}
};
class BitVector {
vector<short>* bitvector; // construct a pointer
public:
BitVector() {
bitvector = new vector<short>(30); // point the pointer to a vector of size 30.
}
vector<short>* get_bitvector() {
return bitvector; //Exception occurs here
}
};
int main() {
BinTree t;
t.insert(10);
}
EXC_BAD_ACCESS happens when you try to access memory which isn't allocated by the application; which the application has no access privilege to.
I suppose the error is because your not adding nodes to your tree. Your just calling them. And over here: if (t==NULL), t->b.get_bitvector()->at(g) is called only if the node address is 0x0, hence the error.
What you should do is, make the logic to add a node if not found in some way and change t==NULL to t!=NULL.
Note: Try using nullptr and ditch NULL when working with pointers.
Your program is failing at two points.
First, you have to check bintree->t for being NOT null:
if (t != NULL) {
t->b.get_bitvector()->at(g) = 1;
}
Second, you have to initialize your bintree->t with a bitvector instead of a NULL:
public:
BinTree() {
root = new BitVector();
}
i was confused with a problem of nested class
#ifndef MINIGRAPH_H_
#define MINIGRAPH_H_
#include<vector>
#include<list>
#include<iostream>
template <typename VEX,typename EDGE>
class MiniGraph
{
public:
class _Node
{
public:
VEX _Vex;
EDGE _Edge;
_Node* next;
};
MiniGraph() {};
MiniGraph(int vex_num);
void add(VEX from, VEX to, EDGE Edge);
//void display();
private:
std::vector<void*> _VecNode;
_Node* NewNode(VEX vex) { _Node* ptr = new _Node;ptr->_Vex = vex;return ptr; }
_Node* NewNode(VEX vex, EDGE edge) { _Node* ptr = new _Node;ptr->_Vex = vex;ptr->_Edge = edge;return ptr; }
};
template <typename VEX, typename EDGE>
MiniGraph<VEX, EDGE>::MiniGraph(int vex_num)
{
int i = 0;
for (i = 0;i < vex_num;i++)
{
struct Node *ptr_tmp = new _Node;
ptr_tmp->next = NULL;
_VecNode.push_back(ptr_tmp);
}
}
template <typename VEX, typename EDGE>
void MiniGraph<VEX, EDGE>::add(VEX from, VEX to, EDGE edge)
{
int i;
_Node* ptr_node = NULL;
for (i = 1;i < _VecNode.size();i++)
{
ptr_node = (_Node*)_VecNode[i];
if (ptr_node->_Vex == from)
break;
}
if (i == _VecNode.size())
{
ptr_node = NewNode(from);
_VecNode.push_back(ptr_node);
}
ptr_node = NewNode(from, edge);
**ptr_node->next = (_Node*)_VecNode[i]->next;//insert node from head**
_VecNode[i]->next = ptr_node;
}
when compiled with
#include "MiniGraph.h"
void main()
{
MiniGraph<int, double> hh;
hh.add(1, 2, 0.1);
hh.add(1, 3, 0.2);
hh.add(2, 3, 0.3);
}
error triggered in ptr_node->next = (_Node*)_VecNode[i]->next;//insert node from head
saying ->next left must point to class/struct/union/generic type;
but _Node was declared 。i was tring to substitute class by struct,but it triggered the same error.
it seems that declaration is not visible.how should i solve this problem?
As #WhozCraig mentioned in the comments above, you have a vector of void*, not a vector of Node*. Therefore there is no member called next. You can type_cast the void* to a Node* to "fix" the problem, but you would be in for a surprise.
The problem start from your main function.
int main()
{
MiniGraph<int, double> hh;
This code will call the default constructor of the MiniGraph class. This means that no Nodes will be created and your vector of Node* will be empty (i.e. std::vector<Node*>::size = 0.
Then you call the add function:
hh.add(1, 2, 0.1);
Inside the add function the following happens:
void add(VEX from_, VEX to_, EDGE edge_)
{
std::size_t i = 0;
for (i=1; i<node_ptrs.size(); i++)
{
if (node_ptrs[i]->vex == from_)
break;
}
After the first call to add(), the vector size = 0, but i = 1. That's because you initialize i=1 inside the for-loop.
Then you check if i == vector::size.
Node *tmp = nullptr;
if (i == node_ptrs.size())
{
tmp = NewNode(from_);
node_ptrs.push_back(tmp);
}
The if-statement above will never be executed, because i = 1 and vector::size = 0.
Finally, you do the following:
tmp = NewNode(from_, edge_);
tmp->next = node_ptrs[i]->next; // this fails because your vector size is 0!
node_ptrs[i]->next = tmp;
The first line works. tmp is a Node* which points to a newly created Node. ok. Then the program fails with a segmentaion fault because tmp->next is trying to shallow copy the pointer in the i element of the vector. Remember now that i = 1 and the vector is still empty, i.e. vector::size = 0. There is no node_ptrs[1] element to copy from. And that's why it crashes.
Example of the code above: https://rextester.com/DTODK86272
There are more problems to consider in your original code... For example:
if only one pointer is meant to point at a certain Node, then use a unique_ptr. You can still have other pointer reading from a unique_ptr, but they won't be able to do anything else.
write constructors that initialize your pointers to nullptr and call a zero initialization on the vex and edge members.
Avoid using int as array indices. What if someone decides to use a negative number as a function argument?
In your implementation you must check if the vector is empty before you start doing anything else. What should happen if the vector is empty?
this is my code:
template <typename T>
struct Node
{
T info;
Node<T>* next;
};
template<typename T>
struct List
{
Node<T>* n;
int curr;
};
List<T> listCreate()
{
List<T> lst;
lst.curr = 0;
cout << lst.n->info;
lst.n->info = 0;
lst.n->next = NULL;
return lst;
}
If I remove the cout << lst.n->info; it causes a segmentation error. What I want to achieve is to simply create a List and have the next values:
lst:
curr = 0
n:
info = 0
next = NULL
But I can't find a way to achieve this, I tried searching on google and also reading about pointers and structures but I cannot find the problem. It might be a simple problem but I can't find it.
Thanks in advance.
You forgot to initialize lst.n. Accessing uninitialized memory or a nullptr is undefined behavior.
You may do something like this:
List<T> listCreate()
{
List<T> lst;
lst.curr = 0;
// new code
lst.n = new Node<T>();
lst.n->next = nullptr;
// end
cout << lst.n->info;
lst.n->info = 0;
lst.n->next = nullptr;
return lst;
}
Please consider avoiding NULL. You should use nullptr in c++.
Remember dereferencing a null or uninitialized pointer is undefined behavior. You are trying to dereference an uninitialized pointer lst.n->info in your code.
I got a question about structs.. C++ is not language what I'm learning but I have a need to do exercise..
I have a struct like this:
struct List
{
int data;
List* next;
};
and I got class and methods with which I can add/remove/printout elements of the struct so for example to view elements I got method:
void Kopa::Print()
{
List *tmp = p;
while (tmp != NULL)
{
cout << tmp->data << endl;
tmp = tmp->next;
}
tmp.struktura;
}
The question is, how can I add and access new struct in List struct?
I guess it the struct will look smth like this but I don't understand how to access it with class methods..
struct List
{
int data;
List* next;
struct NewList
{
int data;
NewList* next;
};
};
First you have to declare a member of that structure, just like you declare other member variables:
struct List
{
struct NewList
{
int data;
};
NewList my_new_list; // Declare a member
};
Then you use it like any other member, just nest the member access as needed:
List l;
l.my_new_list.data = ...;
If you mean how to access the NewList structure inside List to declare a local variable, then you have to use the scope operator :::
List::NewList new_list;
new_list.data = ...;
This looks like an implementation assignment for linked list
Your struct looks like a node struct, not a list. So I will be using struct Node instead of List to avoid confusion.
I don't know where your p comes from, but it is essentially how you would create p in your function.
Node *p = new Node();
p->data = 1;
p->next = NULL;
now if you need to add a new one, do the same thing
Node *q = new Node ();
q->data = 2;
q->next = NULL;
//assign q after p
p->next = q;
You can also create a constructor in your struct
Node (Node *previous, int newData)
{
List *q = new Node ();
q->data = newData;
q->next = NULL;
previous->next = q;
}
make sure you call delete to clean up these pointers when you are done with them
I am trying to remove the left child (10) of a sample binary search tree using two methods:
Method1: By passing pointer to a pointer to the current node.
Method2: By passing address of the pointer to the current node. This does not removes the node, but calling delete corrupts the pointer arrangement, causing a crash while printing the nodes.
The tree looks like this and I am trying to delete 10 and replace it with 5
20
|
10--|---30
|
5---|
I have some understanding of pointers. But still, I am not clear with this behavior of pointers.
#include <iostream>
class Node
{
public:
Node(int key) : leftChild(0), rightChild(0), m_key (key){}
~Node(){}
Node *leftChild;
Node *rightChild;
int m_key;
};
Node* build1234(int, int, int, int);
void print(Node *);
void print1234(Node *);
void removeLeft(Node **nodePtr)
{
Node *oldPtr = *nodePtr;
if(*nodePtr)
{
*nodePtr = (*nodePtr)->leftChild;
delete oldPtr;
}
}
int main()
{
Node *demo1 = build1234(10, 20, 30, 5);
Node *demo2 = build1234(10, 20, 30, 5);
print1234(demo1);
print1234(demo2);
//Method1 - 10 is correctly removed with 5
Node **nodePtr = &demo1;
nodePtr = &(*nodePtr)->leftChild;
removeLeft(nodePtr);
print1234(demo1);
//Method2 - 10 is not removed
Node *node = demo2;
node = node->leftChild;
removeLeft(&node);
print1234(demo2);
return 0;
}
Node* build1234(int B, int A, int C, int D)
{
Node *root = new Node(A);
root->leftChild = new Node(B);
root->rightChild = new Node(C);
root->leftChild->leftChild = new Node(D);
return root;
}
void print(Node *node)
{
if(node)
{
print(node->leftChild);
std::cout << "[" << node->m_key << "]";
print(node->rightChild);
}
}
void print1234(Node *node)
{
std::cout << std::endl;
print(node);
}
Note: This question is not about BST, but pointers. If you see the two calls to removeLeft(nodePtr) and the removeLeft(&node) in the main() function.
How are these two different?
Why the second method fails to achieve the desired result?
In the first case, you are passing an address of a pointer that exists in the tree, so you are modifying the contents of the tree directly.
In the second case, you are passing an address of a variable that is local to main() instead. The tree is not modified, and deleting from the address is accessing stack memory, which is why it crashes
You're overthinking it. All you need is a function removeLeft(Node*) that unhooks the left node and deletes it, recursively:
void removeLeft(Node * p)
{
removeBoth(p->leftChild); // recurse, OK if null
delete p->leftChild; // OK if already null
p->leftChild = 0; // necessary to make recursion terminate
}
void removeBoth(Node * p)
{
if (!p) return;
removeLeft(p);
removeRight(p);
}
If you are bad with pointers consider using smart pointers.
When using smart pointers use shared_ptr<Node> instead of Node * and make_shared(new Node); instead of new Node and remove all deletes. now you can handle pointers without caring for deletes and memory corruption.