A little double-linked list puzzle - c++

Disclaimer
So initially when I posted this, it was a forward list by my error even though I meant to do it as a double-linked list - that's why there are some replies that don't match the problem.
Problem
I was doing some coding and I got to code below. At first glance, it looked like there is nothing wrong with the code, but there is a logical flaw. Can you find it?
class Node {
int val;
Node *next, *prev;
public:
Node(int val, Node *prev, Node *next) {
this->val = val;
this->prev= prev;
this->next = next;
}
int get() {return val;}
Node* getNext() {return next;}
Node* getPrev() {return prev;}
};
int main() {
Node *n1, *n2, *n3;
n1 = new Node(1, NULL, n2);
n2 = new Node(2, n1, n3);
n3 = new Node(3, n2, NULL);
Node *next = n1;
while (next != NULL) {
cout << next->get() << endl;
next = next->getNext();
}
}
The problem is that pointers n1, n2, n3 will get the right addresses only after the memory is allocated with operator new. That means addresses of these pointers are not the same upon Node class instantiation. Eg. in line n2 = new Node(2, n1, n3); n3 would be a bad pointer (because the memory has not been allocated jet and is currently pointing to some nonsense).
Question
Fixing the problem is not an issue, but it made me wonder:
Can you find a way of fixing it without adding any new attribute or method to the class Node?
To go a step further, can you find a way of fixing it without changing any code inside the class Node?
My take on it
To the first question, I thought of the quickest solution. I just made attributes next and prev pointers to pointers and changed the code so that it passes references to the constructor. Also had to change the syntax of the while loop to get dereferenced values.
To the second question, we got one possible solution in replies. We can simply make an array of Nodes. This way we know the exact address of each member as n-th member of an array will have an address of the first member + n - 1;

Eg. in line n2 = new Node(2, n3); n3 would be a bad pointer
There is a simple solution. Fix the order of initialisation so that you start with objects that have no dependencies, and initialise objects after their dependencies have been initialised. In this case, "1" depends on "2" and "2" depends on "3", so therefore:
n3 = new Node(3, nullptr);
n2 = new Node(2, n3);
n1 = new Node(1, n2);
Is it possible to allocate memory in advance?
Sure. It is possible to allocate memory. If you allocate memory before doing something else, then you are allocating memory in advance of that something.
You could create all of the nodes in one go by using an array. You don't even need any dynamic allocation:
Node nodes[] {
{1, nodes + 1},
{2, nodes + 2},
{3, nullptr},
};
Node* next = nodes;
P.S.
I recommend against bare owning pointers. Your example leaks memory.
Don't use NULL in C++. It has been obsoleted by nullptr.
For whatever reason, you've forgotten to initialise the prev member.

I think changing to use pointers-to-pointers is a very very bad idea, and would be extremely odd.
The easist way to do this is to build the tree in reverse:
Node * n3 = new Node(3, nullptr);
Node * n2 = new Node(2, n3);
Node * n1 = new Node(1, n2);
This eliminates n1 using n2 before n2 is created.
However, you still have a problem. At no point are you managing prev. So you might want to do this:
Node(int val, Node *next) {
this->val = val;
this->next = next;
// Add these lines.
if (next != nullptr) {
next->prev = this;
}
}
Note also that using NULL to reference an uninitialized pointer is very old-style C. If you're going to program modern C++, please use nullptr instead, as you see in my examples.
I also did one more change different from yours. I personally don't like this code:
Node *n1, *n2, *n3;
I dislike it for two reasons, both of which will be referenced in at least some corporate style guides. First, some style guides will tell you to reference only one variable per line, not three, like you have. And also, some guides will warn you against leaving your pointers uninitialized. So I broke it out, as you see in my example above.
This last part is just style, but I can't tell you the number of bugs I've chased down due to one or the others of these. For instance, this can hide:
Node *n1, n2, *n3;
Depending on your font size, the sharpness of your eyes, and the phase of moon, you might not see that n2 isn't declared as a pointer. Now, modern compilers will probably catch bad usage, but still... Also, if you agree that all variables should be initialized to something reasonable when created, then your code can get lengthy, and it can be easy to not see you didn't initialize everything.

Seems like you are trying to create a doubly linked list. The bug is you have passed null inside the constructor as an argument. This can be resolved if you allocate memory in the following order:
Node *n3=new Node(3,NULL);
Node *n2=new Node(2,n3)
Node *n1=new Node(1,n2)
Node *next=n1
while(next!=NULL){
cout<<next->get();
next=next->getNext();
}

Related

Why is the output of this code always the same?

Why am I getting the same output in the following for loop in c++.
node* nn = (struct node*)malloc(sizeof(struct node));
for(int i=0;i<10;i++)
{
node* n = (struct node*)malloc(sizeof(struct node));
cout<<&n<<endl;
nn->next = n;
nn =n;
}
Because your n variable is local to the loop body, it is created at the beginning of each iteration, and destroyed at the end of each iteration.
Evidently the compiler decided to reuse the same storage for every incarnation of n, which is why all of them have the same memory address.
Note that &n is the address of n, not its contents. You don't even have to initialize it. Your call to malloc is irrelevant.
If you want to see the value of n, you need to remove the &.
You're outputting &n which is the address of n not the content of n which is probably what you wanted.
NB: The question was edited following my answer, but the same problem remains.
Try this:
#include <iostream>
#include <cstdlib>
struct node {
node* next;
};
int main() {
node* nn = (struct node*)malloc(sizeof(struct node));
nn->next=nullptr;//Initialise so we can clean up nicely...
for(int i=0;i<10;i++)
{
node* n = (struct node*)malloc(sizeof(struct node));
n->next=nullptr;//Initialise so we can clean up nicely...
std::cout<<&n<<"=="<<n<<std::endl;
nn->next = n;
nn =n;
}
//Clean up after ourselves. Not relevant to the question but good practice.
while(nn!=nullptr){
node*n=nn;
free(nn);
nn=n;
}
return 0;
}
Typical output:
0x7ffda1be2058==0x55ffb0b9fc20
0x7ffda1be2058==0x55ffb0ba0c50
0x7ffda1be2058==0x55ffb0ba0c70
0x7ffda1be2058==0x55ffb0ba0c90
0x7ffda1be2058==0x55ffb0ba0cb0
0x7ffda1be2058==0x55ffb0ba0cd0
0x7ffda1be2058==0x55ffb0ba0cf0
0x7ffda1be2058==0x55ffb0ba0d10
0x7ffda1be2058==0x55ffb0ba0d30
0x7ffda1be2058==0x55ffb0ba0d50
The actual output may vary and in principle a compiler isn't required to store n at the same address each iteration. I know of no compiler that doesn't. Anyone?
NB: Using malloc() in C++ is very rarely recommended. The direct substitute for malloc() and free() is new and delete. In practice use std::unique_ptr<> or other self managing construct.
This is only an addition to melpomene's answer, responding to the comments:
How do I create n nodes? Use of vectors is prohibited, so I am creating a linked linked list of n nodes, but the problem is I am unable to create n nodes in a loop.
Actually, your code was less incorrect than you thought, solely you missed one important point:
nn->next = n;
With this instruction, you lost the last reference to what nn pointed to originally and you won't ever be able to re-gain it again...
What you yet need is a second pointer to the element created initially, so you don't lose your list head and thus the rest of the list any more:
node* nn = new node(); // this is the C++ way...
node* head = nn; // now you have a second pointer to the head...
for(int i=0;i<10;i++)
/* [...] */
Now you can access all the nodes you created via the head pointer (as long as you do not move it away from...).
Get rid of the loop and simply use struct *n = malloc (sizeof *n * 10); – David C. Rankin
Another variant: creating 10 elements directly... Assuming node looks like this:
struct node
{
Data data;
node* next;
};
Then you get 10 elements of Data simply by
Data* allData = new Data[10]; // again using the C++ way...
The C++ aproach has another advantage: the elements in the array are already initialised as the default constructor gets called (for primitive data types, see here).

Understanding linked list with C++?

I get the idea of linked list being some kind of way of navigating through some kind of array/list/vector of sorts. I don't think i have the full idea of the concept. I've seen some charts explaining them but I don't seem to understand how they work. So I thought actually looking at the code might help. (My professor doesn't really go over the code that much)
I copied this code from some video.
#include<iostream>
using namespace std;
struct node
{
int num;
node *link;
}*p; // i'm not sure how this pointer was declared
void main()
{
node *root;
root = new node;
root -> num = 5;
root -> link = p;
p = root;
node *q;
for (q = p; q != NULL; q = q -> link)
{
cout << q -> num << endl;
}
}
I guess I don't know what the -> operator does exactly. I know it has something to do with pointers and I'm not sure how that for loop is working.
If someone could take me through the code or if they may have a better example to show me and also if there is any more info that I should know please tell. It would be appreciated.
I think the code is slightly incorrect (or maybe just bad style since it relies on the fact that the pointer is NULL after initialization) as is but I will try to explain this in detail.
Firstly the -> operator evaluates to a dereference followed by a dot ., so root->num is equivalent to (*root).num.
A linked list (in your case a singly linked list) is a structure like follows
NODE{1} --> NODE{3} --> NULL
Here a node is a struct object and has a pointer to another object. These objects together constitute the linked list. As you can see you need some sort of pointer to point to the first element in the linked list. In the example above that element would be the node with the 1 stored in it. This is the root pointer that you have in your code above.
The new is an allocation. You need to place the objects of your linked list somewhere in memory and the new operator helps you find some place in memory (particularly somewhere on the heap) you can store your object. And then it returns a pointer to this location. The best way to learn more about the heap is to research this online. This is an introductory concept (with a lot of "upper level" concepts at the implementation level but you do not have to worry about that at the moment) that is explained very well online. This will likely be better than reading my explanation so I will not explain more about the heap and the stack here. However I think the following links should be helpful
http://www.cplusplus.com/doc/tutorial/dynamic/
http://gribblelab.org/CBootcamp/7_Memory_Stack_vs_Heap.html
http://www.tutorialspoint.com/cplusplus/cpp_dynamic_memory.htm
You also need to know where to stop in the linked list, i.e. you need to know which element is the last element. In the case above the last element is the node with the 3 in it. So this node will not point to another Node object but will rather point to NULL, 0 or the preferred nullptr in C++11 and C++14 (soon also C++17). So you could construct the linked list above with the following code.
#include <iostream>
using std::cout;
using std::endl;
struct Node {
int element;
Node* next;
};
int main() {
Node* root = new Node;
root->element = 1;
root->next = new Node;
root->next->element = 3;
root->next->next = NULL;
for (auto i = root; i != NULL; i = i->next) {
cout << i->element << endl;
}
return 0;
}
Does that make sense?

How do I use an array of pointers in main?

I tried asking my question but I don't appear to be asking it correctly and I have been stuck for 2 months now. (which is sad)
For reference only: I built a linked list from nodes:
struct node {
int number;
node *next; };
To link these in main I used -> to assign values
void insertAsFirstElement(node *&head, node *&tail, int number){
node *temp = new node;
temp->number = number;
temp->next = NULL;
head = temp;
tail = temp; }
Now I am trying to make a skiplist, which should have the same structure as my original node except the node* next should be an array of pointers of type node.
struct node {
int number;
node *next[3];
};
I am getting confused on how to have an array of node pointers. I notice they tend to look like this: node **next and then declared to have memory allocated dynamically. I just want my arrays to be of size 4. So [3].
My problem is how can I create new nodes with the array of node pointers in main() and put something in the first slot of the nodes array?
This does not work for putting things in the array but it does work for putting in the number.
void insertAsFirstElement(node *&head, node *&tail, int number){
node *temp = new node;
temp->number = number;
cout<<temp->number<<endl;
temp->next[0] = tail;
cout<<temp->next[0]<<endl;
head->next[0] = temp;
cout<<head->next[0]<<endl;
}
Please help me.
The -> operator is a shorthand.
Without the -> operator, you would write
(*var).prop;
With the -> operator, you write:
var->prop;
Thus, to store a node in the first position of the list, you write:
void StoreNode(node *node){
node *temp = new node;
temp->next[0]=node;
}
And to retrieve data from a node in the list, you can write:
temp->next[0]->number
which is the same as writing
(*temp).next[0]->number
which is the same as writing
( *((*temp).next[0]) ).number
This line of your code seems a little confused:
void insertAsFirstElement(node *&head, node *&tail, int number){
Remember, you are just passing your function the address of a node. Therefore, all you need is
void insertAsFirstElement(node *head, node *tail, int number){
Inside the function itself, you will have to find the correct location in the list, that is when you get into the ** notations.
The code at a first look seems ok. An array of pointers is just that, an array of elements where each one is a pointer, and you use it exactly with the syntax your code shows.
Note however that when declaring an array of pointers inside a class the elements are not automatically initialized so you probably want to fix the elements that are not used yet to NULL. Moreover in a skip list you're probably going to need to know at which "level" the node has been inserted.
Are you sure your problem is in that part? Often with C++ a mistake doesn't appear right in the point it's done, but much later. This happens because of the "undefined behavior" rule of the language (aka "programmers never make mistakes").

Problems dereferencing node defined by struct

This is for a homework assignment, so explanations (and not direct code) are what I need.
We recently started learned about copy constructors/assignment = operators and such. In the handout we got in class our professor showed us how if you want to deep copy pointers you have to dereference them and copy the values directly.
Eg: (from handout)
class IntCellFixed {
public:
IntCellFixed(int initialValue = 0) { storedValue = new
int(initialValue); }
//v This bit here v
IntCellFixed(const IntCellFixed &source) {
storedValue = new int();
*storedValue = *source.storedValue;
}
//^ This bit here ^
(...)
private:
int *storedValue;
};
This makes sense to me. You have a pointer, and you want to have the value it points to be equal to the value of the pointer you're copying from. So you do * to have it change the value at the address it's pointing at, and not the address itself. That makes sense to me.
So when we went to apply that in lab, I tried a similar thing, but with linked lists instead of just pointers to an integer. Even with the TA's help (with the TA looking at and tweaking my code until it was the "correct" thing), it still did not work and just gave me a segfault. I did not have a chance to ask what exactly the code was supposed to be, and the solution hasn't been posted yet.
We're doing almost the same thing in our homework. Here is the structure of our node (in a binary search tree):
struct Node {
int data;
int count;
Node *left;
Node *right;
};
In my void BinarySearchTree::insert(Node *node,Node *parent, int value) function, I have this bit of code:
if (node == NULL) {
node = new Node();
*node->data = value;
*node->count = 1;
node->left = NULL;
node->right = NULL;
}
When I try to do this, however, it gives me the error: invalid type argument of unary ‘*’ (have ‘int’).
When I take off the *, it runs fine, but doesn't actually save the data for the node outside of the insert function. (ie: when trying to insert multiple values, it always starts with an empty tree, even after I've supposedly inserted values already).
As far as I understand it, I WOULD need to dereference the node because I don't want the address it's pointing to to change, I want what's AT the address to change.
Am I just completely misunderstanding how/when to dereference? If I am, could somebody explain when I would need to, and why I wouldn't need to in this case? Or, if it's a syntax error, could somebody tell me what the syntax should be?

linked list first member variable of node structure always next node

Suppose you have a linked list of nodes as defined below:
C++ code
struct node {
node *next;
int i ;
};
Is there any benefit in making the next pointer as the first member variable of the structure ?
I think that people try this via the above approach (I may be wrong here)
node n, m;
*n=&m;
If above is right, is it right to code like above. What's the right way?
Is there any benefit in making the next pointer as the first member
variable of the structure ?
A very small performance benefit can be reached to reduce the assembly instruction size in loads from and writes to zero offset members, but only in classes without virtual table (vtbl is a omitted first member).
If you want prebuild a scope/global allocated list, its elements can be initialized as mentioned.
You can try it:
struct node {
struct node* next;
int i;
};
node z = {0}, c={&z}, b={&c}, a={&b};
node * stack = &a;
you can find very useful information about liked list searching for 'linux kernel linked list':
Linux Kernel Linked List Explained
How does the kernel implements Linked Lists?
I working now in my own design of 'intrusive node' general purpose containers using c++ templates, perhaps this question might seem interesting.
node n, m;
*n = &m;
is not legal code, perhaps you mean
node n, m;
n.next = &m;
but normally this would be done with dynamic allocation
node* n = new node;
n->next = new node;
because normally you would use node to create a variable length list. Since the length of the list varies there is no way to declare the right number of variables, instead you must allocate the nodes dynamcally.