Compiler says segmentation fault but doesn't tell me which line. From what I understand, a segmentation fault usually means a value at address NULL was attempted to be accessed, but I do not see where that's happening.
#include <iostream>
template <typename T> class SinglyLinkedList
{
struct node
{
T val;
node * next;
};
public:
SinglyLinkedList ();
SinglyLinkedList (T *, size_t);
~SinglyLinkedList ();
void push_back (T);
void print ();
private:
node * _root;
};
int main ()
{
int myArray [] = { 1, 69, -23942, 11111 };
SinglyLinkedList<int> myList(myArray, sizeof(myArray)/sizeof(int));
myList.print();
return 0;
}
template <typename T> SinglyLinkedList<T>::SinglyLinkedList ( )
{
_root = NULL;
}
template <typename T> SinglyLinkedList<T>::SinglyLinkedList (T * arr, size_t n)
{
/* Initialize a singly-linked list of objects of type T from an array of objects of type T */
if (n > 0)
{
node * lastNode = new node;
lastNode->val = *arr;
lastNode->next = NULL;
for (T * pa(arr+1), * pb(arr+n); pa != pb; ++pa)
{
node * thisNode = new node;
thisNode->val = *pa;
thisNode->next = NULL;
lastNode->next = thisNode;
lastNode = thisNode;
}
delete lastNode;
}
else
{
_root = NULL;
}
}
template <typename T> SinglyLinkedList<T>::~SinglyLinkedList ( )
{
node * thisNode = _root;
while (thisNode != NULL)
{
node * temp = thisNode;
thisNode = thisNode->next;
delete temp;
}
}
template <typename T> void SinglyLinkedList<T>::print ( )
{
if (_root == NULL) return;
for (node * thisNode = _root; thisNode != NULL; thisNode = thisNode->next)
{
std::cout << thisNode->val << "->";
}
std::cout << "NULL";
}
Your constructor is wrong.
If n>0 (as in this case) you do a lot of pointer-pointing (which doesn't do what you think it does), but assign no value to _root. Then in print() you dereference _root, which does not point to a valid object; you're lucky all you get is a seg fault.
Related
i'm trying to make a template class for a list in c++. This is something new for me, and i'm stuck. I've written add(T item) method and write() to write whole list on console, but i have random int as output.
Here's my code, if someone could tell me where my mistake is, i will be grateful.
#include <iostream>
#include <stdlib.h>
#include <stdio.h>
using namespace std;
template <class T> class Node {
private:
Node<T> * next;
Node<T> * prev;
T key;
public:
Node(T k) {
next =(Node *) malloc(sizeof(Node));
prev = (Node *)malloc(sizeof(Node));
key = k;
}
Node(T * n, T * p, T k) {
next = n;
prev = p;
key = k;
}
void setNext(Node<T> * n) {
next = n;
}
void setPrev(Node<T> * p) {
prev = p;
}
void show() {
cout << "key= " << key << endl;
}
};
template <class T> class List {
private:
Node<T> * head;
Node<T> * tail;
public:
List() {
head = nullptr;
tail = nullptr;
cout << "list created!" << endl;
}
void add(T item) {
Node<T> node(item);
node.setNext(head);
node.setPrev(nullptr);
if (head != nullptr)
head = &node;
else {
tail = &node;
}
head = &node;
}
void write() {
head->show();
}
};
int main()
{
List<int> lista;
lista.add(8);
lista.write();
return 0;
}
Your add() add a pointer to a Note<T> (node) in the list; but node is destroied when add() ends the execution.
So, when you call write(), that use show(), the pointed memory in undefined (random value).
To avoid this problem, you have to allocate the variable (with new! avoid malloc() with classes), so
Node<T> * nodePnt = new Node<T>(item);
and
head = nodePnt;
tail = nodePnt;
But remeber to delete it.
I tried to search the topic but all the threads I found used while loops.
However I would like to do this recursively:
template <typename S>
struct node {
S data;
node<S> * next;
};
this is the function I invoke in the destructor (pass the head as parameter) of the linked list:
void destroy(node<T> * n) {
if(n->next != NULL){
destroy(n->next);
}
delete n;
}
Unfortunately the result is a segmentation fault.
Can someone help me?
Edit: complete code
#include <iostream>
using namespace std;
template <typename T>
class List {
private:
template <typename S>
struct node {
S data;
node<S> * next;
};
node<T> * first;
node<T> * get_last_p() {
if(first != NULL){
return get_last(first);
}
return NULL;
}
node<T> * get_last(node<T> * n) {
if(n->next != NULL) {
return get_last(n->next);
} else {
return n;
}
return NULL;
}
void destroy(node<T> * n) {
if(n->next != NULL){
destroy(n->next);
}
delete n;
}
public:
List() {first->next = 0;}
~List() {destroy(first);}
void add(T element) {
node<T> * new_element = new node<T>;
new_element->data = element;
if(first == NULL){
first = new_element;
} else {
get_last_p()->next = new_element;
}
}
T get_last() {
return get_last_p()->data;
}
T get_first() {
return first->data;
}
};
From what I can see, in List's constructor, first is not initialized, and is then immediately accessed. That is undefined behavior.
Even if first was somehow initialized to null in an unreliable way, and that first->next = 0; wouldn't crash somehow, you'd also fail in your destructor's destroy, since destroy assumes its original argument is not null.
I assume you meant to
List() : first{ new node{} } { first->next = nullptr; }
If first is not meant to hold a value, then you're going to have to refactor your code to first initialize first to null - there's no working around that - and handle the case where first is null explicitely in all your code. You cannot assign first->next of a null, invalid or undefined pointer.
My question is why do I need to dereference and reference a pointer for the following code to work? Doesn't ref/deref cancel each other?
I would really appreciate if anyone could explain it like I'm five :)
Code:
template <typename T>
class binNode {
private:
T key;
public:
binNode * left;
binNode * right;
binNode * parent;
binNode() {
this->left = NULL;
this->right = NULL;
this->parent = NULL;
}
// arg constructor:
binNode (T key) {
this->key = key;
this->left = NULL;
this->right = NULL;
this->parent = NULL;
}
T getKey() {
return this->key;
}
void setKey(T key) {
this->key = key;
}
};
template<typename T> class Tree {
private:
binNode <T> *root;
public:
Tree() {
this->root = NULL;
}
Tree(binNode <T> * node) {
node->parent = NULL;
this->root = node;
}
/* THIS IS THE PART I DON'T GET */
void addNode(binNode<T> *&x, binNode<T> * node) { // what's up with the *&???
if (x == NULL) {
x = node;
return;
} else if (x->getKey() == node->getKey()) {
node->left = x;
node->parent = x->parent;
x->parent = node;
return;
}
if (node->getKey() < x->getKey()) {
addNode(x->left, node);
} else {
addNode(x->right, node);
}
}
void addNode(binNode<T> * node) {
addNode(this->root, node);
}
binNode<T> * treeSearch(binNode<T> * x, T key) {
if (x == NULL || key == x->getKey()) {
return x;
}
if (key < x->getKey()) {
return treeSearch(x->left, key);
} else {
return treeSearch(x->right, key);
}
}
void printOrdered() {
inorderTreeWalk(root);
cout << endl;
}
void inorderTreeWalk(binNode<T> * node) {
if (node != NULL) {
inorderTreeWalk(node->left);
cout << node->getKey() << '\t';
inorderTreeWalk(node->right);
}
}
};
Here is the main function (#inlude is not included)
int main() {
Tree<int> T (new binNode<int>(10));
// Tree<int> T = new binNode<int>(10);
T.addNode(new binNode<int> (11));
T.addNode(new binNode<int> (9));
T.addNode(new binNode<int> (8));
T.addNode(new binNode<int> (12));
T.printOrdered();
}
That's not a reference / dereference of a pointer, it's a reference to a pointer. It is necessary because...
void addNode(binNode<T> *&x, binNode<T> * node) {
if (x == NULL) {
x = node; // ...here...
return;
} else // ...
...you are assigning to the parameter x.
If you hadn't passed the pointer x by reference, you would assign to the local copy of the parameter:
void addNode(binNode<T> * x, binNode<T> * node) {
if (x == NULL) {
x = node; // this acts on the local copy only, and thus does nothing.
return;
} else // ...
Via the pointer (without the reference), you get a local copy of the address. Which means you can manipulate the value behind the pointer (in this case *x) which would change. But if you change the address itself, the address would behave like a local copy and you lose the address-changes after leaving the method.
I made a linked list class to practice generic programming. The following code compiles, but my test in the main isn't printing anything to the console, like it should be. Any idea why? I know that Stack Overflow doesn't like the "fix my bug" posts, but I'm really at a loss here.
#include <iostream>
template <class T> class List {
public:
List();
~List();
int getSize();
void push_back(T);
bool contains(T);
private:
struct node {
T val;
node* next;
};
int size;
node* firstNodePtr;
node* lastNodePtr;
};
template <class T> List<T>::List() {
size = 0;
firstNodePtr = NULL;
lastNodePtr = NULL;
}
template <class T> List<T>::~List() {
node* curNodePtr = firstNodePtr;
node* nextNodePtr;
while (curNodePtr) {
nextNodePtr = curNodePtr->next;
delete curNodePtr;
curNodePtr = nextNodePtr;
}
}
template <class T> int List<T>::getSize() {
return size;
}
template <class T> void List<T>::push_back(T newElement) {
if (size == 0) {
firstNodePtr = new node;
firstNodePtr->next = lastNodePtr;
firstNodePtr->val = newElement;
++size;
} else {
node* newNode = new node;
lastNodePtr->next = newNode;
newNode->val = newElement;
newNode->next = NULL;
++size;
}
}
template <class T> bool List<T>::contains(T thisElement) {
node* curNodePtr = firstNodePtr;
while (curNodePtr) {
if (curNodePtr->val == thisElement)
return true;
curNodePtr = curNodePtr->next;
}
return true;
}
int main (int argc, char* const argv[]) {
List<int> myList;
myList.push_back(5);
myList.push_back(18);
std::cout << myList.getSize() << std::endl;
std::cout << myList.contains(18);
return 0;
}
Look here:
if (size == 0){
firstNodePtr = new node;
firstNodePtr->next = lastNodePtr;
firstNodePtr->val = newElement;
++size;
}
You forgot to assign a value to lastNodePtr. So when you try to dereference it in the second call to push_back, you get undefined behavior.
In the block handling the creation of the initial node in push_back,
you don't want this line:
firstNodePtr->next = lastNodePtr;
Also, you need to set lastNodePtr = firstNodePtr; at the end of push_back
I'm defining a binary search tree class like this:
template <class T>
class BSTNode
{
public:
BSTNode(){
right = left = 0;
}
BSTNode(const T& el, BSTNode * l = 0, BSTNode * r = 0)
{
val = el; left = l; right = r;
}
T val;
BSTNode * right;
BSTNode * left;
};
template <class T>
class BST
{
public:
BST(){ root = 0;}
void Insert(const T& el);
private:
BSTNode<T> * root;
};
and I implement the Insert() function like this:
template <class T>
void BST<T>::Insert(const T& el)
{
bool bEqual = false;
BSTNode<T> * p = root;
while(p)
{
if(el == p->val)
{
bEqual = true;
return;
}
if(el < p->val)
{
// go left
p = p->left;
}
if(el > p->val)
{
// go right
p = p->right;
}
}
if(!p)
{
std::cout << "creating new node " << el << "\n";
p = new BSTNode<T>(el);
}
}
Why does the root pointer variable stay at 0, and not the address of the new object?
You never do root = ?; in your code; also, p = new BSTNode<T>(el); leaks memory.
My guess is that you wanted to p to be a reference to pointer, so you could change the original pointer.
BSTNode<T> *& p = root; // watch out, it won't solve anything
But, in such case, p is not-reassignable. You may want to check if pointer you assign to p is null and just insert the new value in correct place (eg. p->left = new BSTNode<T>(el);) and reassign p only when given pointer is not null.
I mean:
template <class T>
void BST<T>::Insert(const T& el)
{
bool bEqual = false;
BSTNode<T> * p = root;
if (p == 0)
{
root = new BSTNode<T>(el);
return;
}
while(true)
{
if(el == p->val)
{
bEqual = true;
return;
}
if(el < p->val)
{
if (p->left == 0)
{
p->left = new BSTNode<T>(el);
return;
}
p = p->left;
}
if(el > p->val)
{
if (p->right == 0)
{
p->right = new BSTNode<T>(el);
return;
}
p = p->right;
}
}
}
Because at the construction of object
the statement
p= root
initializes p as a null pointer..
You create a new object and pass its address to p instead of root...
The thing is p is just a copy of root and not a reference to this pointer..