I have a structure with two pointers that I am storing inside of an array of the same type. I am unsure of how to access the pointers in each specific index of the array.
class List
{
public:
List();
private:
struct L_Node
{
L_Node *next;
L_Node *prev;
int iValue; // not actually doing anything in this example
}
L_Node head[4];
L_Node tail[4];
}
In the constructor, I am wanting head[0] next to be pointing to tail[0] next, head[1] next to tail[1] next and so on, with *prev to be pointing from tail to head to form a doubly linked list. For head, prev = NULL, and in tail next=NULL. In between the head and tail arrays, I am trying to have some dynamic instances of L_Node.
As of now, in my constructor, I have
head->next = new L_Node;
head->prev = NULL;
tail->next = NULL;
tail->prev = new L_Node;
head->next->next = tail;
tail->prev->prev = head;
It compiles, however I am unsure of how it is behaving. Is head[0] pointing through the dynamic struct to tail[0] and so on?
Thanks in advance for any help or tips.
EDIT:
would a typedef for a pointer such as
typedef L_Node *L_Ptr;
be of help?
From your description, this is what you need in the constructor of List:
List::List()
{
for (int i = 0; i != 4; ++i )
{
head[i].next = tail[i];
tail[i].prev = head[i];
}
}
I would add a constructor in L_Node to have sane initial values for its member data.
L_Node() : next(NULL), prev(NULL), iValue(0) {}
Related
Today I was taught Linked list in class and I wanted to implement it on my own.
Here's the part of the code that I wrote. Note that traverseLL traverses the Linked list and insertAtEnd inserts a new node at the end of the linked list.
I believe I can implement Linked list logic / methods / functions on my own. But my question is, inside insertAtEnd function when I create a newNode with the parameters - my data to be inserted, and nullptr (because inserting at the end), It inserts garbage values (or memory addresses maybe) in my node, ignoring the data passed to the constructor.
using namespace std;
#define NL '\n'
class Node {
public:
int data;
Node* next;
Node (int data, Node* nextPtr=nullptr) {
data = data;
next = nextPtr;
}
};
void insertAtEnd(Node* &head, int data) {
Node* newNode = new Node(data, nullptr); // <---- Issue in this line
// When I do as above, my linkedlist nodes always store garbage values and not the data being passed.
// However, when I un-comment the below line, I get the correct output.
// newNode->data = data;
if (head == nullptr)
head = newNode;
else {
Node* temp = head;
while (temp->next != nullptr)
temp = temp->next;
temp->next = newNode;
}
}
void traverseLL(Node* head) {
if (head == nullptr)
return;
while (head->next) {
cout << head->data << " -> ";
head = head->next;
}
cout << head->data << NL;
}
int main() {
Node* head = nullptr;
insertAtEnd(head, 10);
insertAtEnd(head, 20);
insertAtEnd(head, 30);
traverseLL(head);
return 0;
}
For example, the output for the above code when keeping newNode->data = data line commented, is :
16259544 -> 16258392 -> 16258392
But when I un-comment that line, my output becomes, which is intended:
10 -> 20 -> 30
Why is this happening? Even though I've defined my constructor, why is it not working?
I think the cause for this is the statement data = data in the constructor.
Reason for this:
Before executing the first statement of constructor, the member variables of the class are allocated memory and contain junk/default values, and when the statement data = data is seen the compiler changes the parameter but not the member variable.
As a result, you are seeing junk/garbage values.
To resolve this we can either explicitly specify the member using this or use member initialization syntax.
You can use any of the following workarounds.
Workarounds:
You can change your class constructor code like any of the below formats:
1.
class Node {
public:
int data;
Node* next;
Node (int data, Node* nextPtr=nullptr) {
this->data = data; // we are explicitly specifying which data to use
next = nextPtr;
}
};
class Node {
public:
int data;
Node* next;
Node (int d, Node* nextPtr=nullptr) {
data = d; // as the member variable and local variable are of different names, no conflict
next = nextPtr;
}
};
class Node {
public:
int data;
Node* next;
// use the member initialization syntax
// Here we are initializing the data while allocating memory itself,
// so answer is perfectly right!
Node (int d, Node* nextPtr=nullptr) : data(data), next(nextPtr) {}
};
More on the member initialization and constructor:
https://en.cppreference.com/w/cpp/language/constructor
How do C++ class members get initialized if I don't do it explicitly?
Hope this helps,
Thanks.
When I call the default constructor for my class LinkedList I attempt to assign values to the head node of the linked list before any other operations occur. I have isolate the error, via debugging, to the instructions in the default constructor. As soon as
head -> next = NULL;
head -> RUID = 0;
head -> studentName = "No Student in Head";
are called the program crashes. This occurs when I call the default constructor in main.
Here is my class declaration and my struct declaration along with the default constructor:
struct Node
{
string studentName;
int RUID;
Node* next;
};
class LinkedList
{
private:
// Initialize length of list
int listLength;
public:
// Head of the list, which points to no data yet
Node *head;
LinkedList();
bool insertNode(Node* newNode, int position);
int generateRUID();
};
LinkedList::LinkedList()
{
head -> next = NULL;
head -> RUID = 0;
head -> studentName = "No Student in Head";
listLength = 0;
}
I believe this all of the relevant code to this issue. If someone could shed light on this it would be much appreciated.
LinkedList::head is a Node*, not a Node and you don't initialize it, so the object (binary, in-memory) representation is undefined and is therefore dangerous to dereference.
Change your LinkedList to explicitly initialize the head member. I recommend storing it by-value (as Node) rather than as a heap-allocated value (Node*) for simplicitly, unless you know you'll need to reparent nodes.
Using Node*:
LinkedList::LinkedList() :
head( Node() ),
listLength( 0 )
{
this->head->next = nullptr;
this->head->RUID = 0;
this->head->studentName = "No Student in Head";
}
Code:
#include <iostream>
using namespace std;
class Node {
public:
Node *next;
int value;
Node(int value) {
this->next = nullptr;
this->value = value;
}
};
class LinkedList {
private:
Node *head;
Node *tail;
public:
LinkedList() {
this->head = nullptr;
this->tail = nullptr;
}
void addToEnd(int value) {
if(head == nullptr)
this->head = new Node(value);
else
this->tail->next = new Node(value);
this->tail = this->tail->next;
}
void print() {
for(Node *n = this->head; n != nullptr; n = n->next)
cout<<n->value<<" ";
cout<<endl;
}
};
int main() {
LinkedList *list = new LinkedList();
list->addToEnd(21);
list->addToEnd(25);
list->addToEnd(56);
list->addToEnd(24);
list->print();
return 0;
}
My problem is, when I am assigning an instance of Node to this->head, the program crashes. Is there different way of assigning an instance to a pointer that was initially nullptr?
This code structure works fine on Java, I came from Java, that is why I have difficulty on C++'s pointers.
EDIT
I pasted the right code now, I'm sure. Sorry.
Ok, I have solved the problem. So, the problem is not about allocating an object to a class member, but, the problem is accessing a nullptr member: this->tail.
I edited this method, and the program now runs the way I wanted.
void addToEnd(int value) {
Node *n = new Node(value);
if(head == nullptr)
this->head = n;
else
this->tail->next = n;
this->tail = n;
}
Thanks for your help people, this question is now SOLVED. :)
I don't know about "it crashes", but the following line is not valid:
this->head = Node(value);
head is a pointer-to-Node but you're trying to assign a Node to it. Even if this automatically took the address of the temporary you created on the RHS (which it doesn't), you'd have a pointer to a local variable that doesn't exist for very long.
You should be getting a compilation error for that.
You'd have to use new to create a new object dynamically — be sure to write code to free that memory later!
You're similarly messing up dynamic memory allocation in main, where you have a needless memory leak. LinkedList list; will do fine, there.
You need to allocate memory for your Node instances. The quickest way is to call new Node(value) wherever you call Node(value). However if I were you I'd consider using shared_ptr<Node> rather than plain pointers.
I have a linked_list and currently my destructor is not working properly. Not entirely sure why.
Can somebody explain me how to solve this?
class linked_list {
private:
struct node
{
// String in this node
std::string data;
// Pointer to next node
struct node *next;
};
//First item in the list
struct node *first;
Here is my destructor
linked_list::~linked_list(void)
{
while (first)
{
delete first;
first = first->next;
}
}
The problem lies here:
delete first;
first = first->next;
When you delete first, but then try to access first->next. Cache first->next into a temp variable of type node*, then do delete first to fix this:
struct node* temp;
while (first != NULL)
{
temp = first->next;
delete first;
first = temp;
}
change to
linked_list::~linked_list(void)
{
struct node *next;
while (first != NULL)
{
next = first->next;
delete first;
first = next;
}
}
When you 'delete' first, you actually clear all the links from it. Now, if you try to access some other node using this, will not produce the required result.
First, you have to point that node with some other pointer, so that you still have some link which you can access later.
I've just implemented the Linked List. It works perfectly fine but even tough I've seen notation I am unable to create working destructor on Node, that's why it's unimplemented here in code.
I need to implement working destructor on node
Destructor of List but this one is simple I will just use the destructor from Node class(but I need this one).
Make the List friendly to Node so I will not have to use getNext(), but I think I can
handle it myself(not sure how, but I'll find out).
Please look at the code it is perfectly fine, just will work if you copy it.
#include <cstdio>
#include <cmath>
#include <iostream>
#include <stdio.h>
#include <string.h>
using namespace std;
class Node {
public:
Node(Node* next, int wrt) {
this->next = next;
this->wrt = wrt;
}
Node(const Node& obiekt) {
this->wrt = obiekt.wrt;
this->next = obiekt.next;
}
~Node() {}
void show() {
cout << this->wrt << endl;
}
int getWrt(){
return this->wrt;
}
Node* getNext(){
return this->next;
}
void setNext(Node* node){
this->next = node;
}
private:
Node* next;
int wrt;
};
class List{
public:
List(int wrt){
this->root = new Node(NULL, wrt);
}
List(const List& obiekt){
memcpy(&this->root,&obiekt.root,sizeof(int));
Node* el = obiekt.root->getNext();
Node* curr = this->root;
Node* next;
while(el != NULL){
memcpy(&next,&el,sizeof(int));
curr->setNext(next);
curr = next;
next = curr->getNext();
el = el->getNext();
/* curr->show();
next->show();
el->show(); */
}
}
void add(int wrt){
Node* node = new Node(NULL, wrt);
Node* el = this->root;
while(el->getNext() != NULL){
//el->show();
el = el->getNext();
}
el->setNext(node);
}
void remove(int index){
Node* el = this->root;
if(index == 0){
//deleting old one
this->root = this->root->getNext();
}
else{
int i = 0;
while(el != NULL && i < index - 1){
// el->show();
el = el->getNext();
i++;
}
if(el!=NULL){
Node* toRem = el->getNext();
Node* newNext = toRem->getNext();
el->setNext(newNext);
//deleteing old one
}
}
}
void show(){
Node* el = this->root;
while(el != NULL){
el->show();
el = el->getNext();
}
}
~List(){}
private:
Node* root;
};
int main(){
List* l = new List(1); //first list
l->add(2);
l->add(3);
l->show();
cout << endl;
List* lala = new List(*l); //lala is second list created by copy cosntructor
lala->show();
cout << endl;
lala->add(4);
lala->remove(0);
lala->show();
return 0;
}
I suggest you to start with implementing destructor of List. Since you dynamically allocated memory by using new, you should free it by using delete. (If you used new[], it would be delete[]):
~List()
{
Node* currentNode = this->root; // initialize current node to root
while (currentNode)
{
Node* nextNode = currentNode->getNext(); // get next node
delete currentNode; // delete current
currentNode = nextNode; // set current to "old" next
}
}
Once you have proper destructor, you should try whether your copy constructor is correct:
List* lala = new List(*l);
delete l; // delete list that was used to create copy, shouldn't affect copy
you will find out that your copy constructor is wrong and also causes your application to crash. Why? Because purpose of copy constructor is to create a new object as a copy of an existing object. Your copy constructor just copies pointers assuming sizeof(Node*) equal to sizeof(int). It should look like this:
List(const List& list)
{
// if empty list is being copied:
if (!list.root)
{
this->root = NULL;
return;
}
// create new root:
this->root = new Node(NULL, list.root->getWrt());
Node* list_currentNode = list.root;
Node* this_currentNode = this->root;
while (list_currentNode->getNext())
{
// create new successor:
Node* newNode = new Node(NULL, list_currentNode->getNext()->getWrt());
this_currentNode->setNext(newNode);
this_currentNode = this_currentNode->getNext();
list_currentNode = list_currentNode->getNext();
}
}
Also your function remove is wrong since it "removes" reference to some Node but never frees memory where this Node resides. delete should be called in order to free this memory.
"I need to implement working destructor on node" - No, you don't. Node itself doesn't allocate any memory, thus it shouldn't free any memory. Node shouldn't be responsible for destruction of Node* next nor cleaning memory where it's stored. Don't implement destructor nor copy constructor of Node. You also want to read this: What is The Rule of Three?
"Make the List friendly to Node so I will not have to use getNext()" - You want to say within Node class, that class List is its friend:
class Node
{
friend class List; // <-- that's it
Note that from these 5 headers that you include your code requires only one: <iostream>.
Also note that writing using namespace std; at the beginning of the file is considered bad practice since it may cause names of some of your types become ambiguous. Use it wisely within small scopes or use std:: prefix instead.
The linked list destructor will be called either when delete is used with a previously allocated pointer to a linked list or when a linked list variable goes out of scope (e.g., a local variable is destroyed when returning from a function).
The destructor for the linked list should be responsible to free the memory you previously reserved for the nodes (i.e., using add operation). So, basically, you need to traverse the list of nodes and apply the delete operation on each one of them. There is a little trick: when you are about to delete a node you must be careful not to lose the pointer to the next element (when a node is deleted you cannot be sure that next member will still be valid).
If you want to create a destructor for your Node, it should be quite simple actually.
Here it is:
class Node {
private:
int wrt;
Node* next;
public:
Node(Node* next, int wrt) {
this->next = next;
this->wrt = wrt;
}
// Your desired destructor using recursion
~Node() {
if ( next != NULL )
delete next;
}
};
It's that simple :)
Basically, right before the Node is deleted, if next is not empty, we delete next, which will again call the destructor of next, and if next->next is not empty, again the destructor gets called over and over.
Then in the end all Nodes get deleted.
The recursion takes care of the whole thing :)