Pointer to the element in the list VS element itself - c++

I have found this code on the internet and I need a little help with it.
Here's the code:
#include<iostream>
using namespace std;
/* Linked list structure */
struct list {
struct list *prev;
int data;
struct list *next;
} *node = NULL, *first = NULL, *last = NULL, *node1 = NULL, *node2 = NULL;
class linkedlist {
public:
/* Function for create/insert node at the beginning of Linked list */
void insert_beginning() {
list *addBeg = new list;
cout << "Enter value for the node:" << endl;
cin >> addBeg->data;
if(first == NULL) {
addBeg->prev = NULL;
addBeg->next = NULL;
first = addBeg;
last = addBeg;
cout << "Linked list Created!" << endl;
}
else {
addBeg->prev = NULL;
first->prev = addBeg;
addBeg->next = first;
first = addBeg;
cout << "Data Inserted at the beginning of the Linked list!" << endl;
}
}
What I don't understand is when he is making the new Node object (in this case it's addBeg) he is putting a pointer operator in front of it. And how I'm seeing it now, shouldn't the object be created without the '*' before it's name and with the data, pointer to next and pointer to the previous one, unlike the pointer to the node in the list which should only contain address of the node, without any other data ? If that's not the case, then what is the thing that differs the pointer to the node in the list from the node itself ?

The way it's been done in the code is correct. You are having an incorrect understanding in that the data of a node cannot be accessed through the pointer to that node.
If addBeg is the pointer pointing to the node returned by new list, then the data of that node can be accessed using the operator ->:
list.data is equivalent to addBeg->data.
If that's not the case, then what is the thing that differs the pointer to the node in the list from the node itself ?
=> addBeg is the pointer pointing to an object, that object being returned by new List.

You didn't interpret this C++ declaration correctly... the meaning of code
list *addBeg = new list;
is
list* addBeg;
addBeg = new list;
list* in other words is the type of addBeg.
Note that the rules are indeed strange, because while the * being logically attached to first list to form the type, the meaning of
list *a, b;
will declare a to be a "pointer to list" and b to be a "instance of list" instead (so the meaning is attached to list but the star itself is attached to a).
Some programmers go quite far about this and:
They always put the star attached to the type (on the left)
They never declare two variables in the same construct
In my experience after writing enough code this interpretation problem will however disappear and even crazy syntax rule for C/C++ declarations will be reasonable easy to read (at least in simple cases).

Related

38:10: error: member reference base type 'Node *' is not a structure or union *prev->next = temp;

Code is to insert element at the end position of link list. I am passing pointer to the Node pointer to insert method while doing so I am getting the error member reference base type 'Node *' is not a structure or union on line number 38, which is *prev->next = temp;. Please explain the issue and if you provide the solution on the same logic, it will be better.
#include "iostream"
using namespace std;
struct Node {
int data;
Node* next;
};
void insertElement(Node**, Node**, int);
void printLinkList(Node** head);
int main(int argc, char const *argv[]) {
Node *head = NULL, *prev = NULL;
int num, pos;
char controller;
cout << "To add element to link list press y, to quit press any other key: ";
cin >> controller;
while(controller == 'y') {
cout << "Enter element: ";
cin >> num;
insertElement(&head, &prev, num);
cout << "To add next element to link list press y, to quit press any other key: ";
cin >> controller;
}
printLinkList(&head);
return 0;
}
void insertElement(Node **head, Node **prev, int num) {
Node *temp = new Node();
temp->data = num;
temp->next = NULL;
if(*head == NULL) {
*head = temp;
}
if(*prev != NULL) {
*prev->next = temp;
}
*prev = temp;
}
void printLinkList(Node** head) {
Node* temp = *head;
while(temp != NULL) {
cout << temp->data << ", ";
temp = temp->next;
}
cout << endl;
}
The error message would be self-explanatory if your expression was less complex. Still, it is reasonably straight-forward when taken out of context.
member reference base type 'Node *' is not a structure or union
This says that at some point you tried to access the member of a pointer to Node, which is not allowed because only structures and unions have members. (The compiler is using "structure" to cover both struct and class.) In particular, pointers do not have members.
Hopefully this rings true. If temp is a Node*, then the expression temp.data does not make sense; you need first to de-reference the pointer, as in (*temp).data or the equivalent temp->data. So what is going on in your code?
At the problematic point in your code, you have a pointer-to-pointer, which is often not the best approach. The pointer-to-pointer, prev, appears in the sub-expression prev->next, which is equivalent to (*prev).next. Consider that last expression. Since prev is Node**, a single de-reference gives Node* which is the situation from above: trying to access the next field does not make sense unless you first de-reference the pointer, as in (**prev).next. This is close to what you wrote, but not quite.
The correct expression, (**prev).next is equivalent to (*prev)->next. Your expression, *prev->next, is equivalent to *(prev->next) or *((*prev).next). There is a difference in the order of evaluation. This difference is one reason pointers-to-pointer are challenging to manage correctly. (The language is not designed to succinctly accommodate pointers-to-pointer-to-structure. Instead, it assumes the more likely scenario for two levels of indirection is pointer-to-structure-with-pointer-member.)
Since you are coding in C++ instead of C, there is a nifty language feature that helps avoid this problem. Have insertElement accept Node pointers by reference instead of by address. This reduces the complexity of your expressions, removing your current problem, and addresses the future problem where you never checked if the function's parameters are null. (You have a check for *head being null, but that check blows up if head itself is null.)
void insertElement(Node *&head, Node *&prev, int num);
With this change, occurrences inside the function body of head* become head, of prev* become prev, and the call to the function becomes insertElement(head, prev, num); (no address-of operator). You get simpler syntax so you can focus on the logic of inserting an element.
See also Meaning of *& and **& in C++.

Local variable pointer overwritten on each method call

I am currently reading a book on data structures and learning c++ on the side. I am trying to implement a simple linked list. Below is some code for a list that can take a maximum of two elements (in order to isolate my problem).
What is going wrong is the pointer declaration to the next node in the list. When I create a new Node instance and create a pointer to it, the pointer stays the same on each method call, so all elements in the list point to the same node. However, if I create a pointer directly, everything works as expected.
What I am guessing is that I have some fundamental misunderstanding of pointers, references and the new keyword.
Feel free to run the code below. The working code is commented out.
#include <iostream>
using namespace std;
template <typename T> class Node {
public:
Node(T nvalue) {
this->value = nvalue;
this->next = NULL;
}
T value;
Node *next;
};
template <typename T> class LinkedList {
public:
Node<T> *head;
LinkedList() {
this->head = NULL;
}
void append(T newVal) {
// Correct
// Node<T>* newNode_ptr = new Node<T>(newVal); // newNode_ptr is different on each call
// Incorrect!?
Node<T> newNode = Node<T>(newVal);
Node<T> * newNode_ptr = &newNode; // newNode_ptr is the same on each call
cout << "New Node Address: " << newNode_ptr << endl;
if (!(this->head)) {
this->head = newNode_ptr;
cout << "Value 0: " << this->head->value << endl;
} else {
this->head->next = newNode_ptr;
cout << "Value 0: " << this->head->value << endl;
cout << "Value 1: " << this->head->next->value << endl;
}
}
};
int main() {
LinkedList<int> list = LinkedList<int>();
list.append(21);
cout << "..." << endl;
list.append(42);
}
Note that this code is not exactly well designed (some stuff should be private, using namespace std should be avoided). I am familiar with python so this pointer stuff is a little overwhelming. Thanks for your help in advance!
Node<T>* newNode_ptr = new Node<T>(newVal);
This is the more correct way of the two. It is normal that the address of newNde_ptr is different, it's what you want. Each node is a different node, two different objects cannot have the same address! The version without new gives the same address because you are creating the objects on the stack. This will not work, every node is destroyed at the end of the append function. You will see unusual results (if it doesn't crash) if you move the printing portion of append to another function. Since all your pointers point to the same address (in your case) and at the point where you print out the values that address just so happens to be a valid Node, you do not see a crash. However, this is undefined behavior and can change for any number of reasons.
The difference between free-store (heap for malloc/free) and the stack is a fundamental concept of c++. You should read about it here.
The reason I saw more correct way of the two is that you still have to remember to delete your nodes. A better way would be to use std::unique_ptr instead of raw pointers to avoid that (and may other) mistakes that using raw pointers encourages.
// Node * next; becomes
std::unique_ptr<Node> next;
// Node<T> newNode = Node<T>(newVal); becomes
newNode = std::make_unique<T>(newVal);

Linked List of sorted names C++

I have a problem with a linked list that I had to create.
The program should take in user input of names and then put them into a linked list. This list should be sorted alphabetically, so when a new node is added it should go to the right position.
My code looks like this for now:
struct node
{
string info;
node *next;
};
class Passenger
{
private:
node* pname;
public:
void insert(string);
Passenger();
};//closes Passenger class
Passenger::Passenger()
{
pname = new node;
pname -> info = "ABC";
pname -> next = NULL;
}
void Passenger::insert(string name)
{
node *temp, *p, *s;
p = pname;
s = pname;
temp = new node;
temp->info = name;
if(p-> info == "ABC") //new pname linked list, put temp at the front
{
p->info = name;
p->next = NULL;
}
//if there is already one in the list
while(s != NULL)
{
cout<<"inside while loop"<<endl;
//if new node goes to left
if(temp->info < s->info)
{
temp->next = p;
pname = temp;
}//closes if
if(temp->info > s->info)
{
if(p->next != NULL)
{
s = s->next;
if(s->next == NULL)
s->next = temp;
}//closes if
}//closes if
p = p->next;
s = s->next;
}//closes while
I really don't know how to change it that it works. I got it done when there was one node in the list and then add a second one. But if there are 2 nodes already there I don't know how to sort a third or fourth node in.
Dave
BTW, representing an empty list with a sentinel node containing "ABC" is ridiculous. What if someone wants to store a list that starts with that? Using a NULL pointer to represent an empty list is a near-universal convention.
Also, the nodes don't have to be a different type. The list class itself can be a node. So an instance of the class is just an instance of the first node, with a pointer to the rest of the list. Or, to better handle empty lists, you can have a container class that keeps pointers to the head (and optionally tail, for fast tail-insertion). Implementation helper-functions can be member functions of the nodes, not the container class, if you like, so you can call them on any sub-list.
When I was learning linked-lists, I often found it helped to draw circles for nodes and arrows for pointers on a piece of paper, like in the data structures textbook. Then you don't have to keep as much up-in-the-air mentally while you think through the process and any special-cases (beginning or end of the list).
You could break the problem down into two parts: the search, and the insert.
Your search function should return a pointer to the node before the insert position. i.e. the last node with a string that compares less than the one you're inserting. Your loop in that function then needs to either look ahead to the next element, or keep a prev pointer. Either way, you need to get back to the node before the one that stops the loop.
Inserting after a node is pretty easy. There's a special case when you need to insert a new head of the list, because there's no node to modify to point to the new current list. But you don't need to care whether the node you're inserting after was the end of the list or not.
You can reduce the amount of special cases by using a "dummy" node pointing to the actual first element. This trick might not work for a comparison-based insert, compared to an InsertNth. My answer on that question breaks things down into find and insert, and is written in a C-like style even though that was a Java code-review question. See the InsertAfter and InsertBefore methods.

How to change LinkedList head pointer globally and not locally

I have TWO implementations of this.
Why does this particular implementation NOT work? I have a pointer to a pointer and im changing the inside point but it doesn't retain the change in the main function
#include <iostream>
using namespace std;
struct Node {
int value = 4;
Node* next;
};
void insertFront(Node*, Node**);
int main(){
Node head;
head.value = 32;
head.next = nullptr;
Node** headptr = new Node*;
(*headptr) = new Node;
*(*headptr) = head;
(*headptr)->value = 32;//redundant, I know
(*headptr)->next = nullptr;//redundant, I know
cout << head.value << endl;
insertFront(new Node, headptr);
cout << head.value << endl;
system("pause");
return 0;
}
void insertFront(Node* newHead, Node** head2){
cout << "Inside before swap " << (*head2)->value << endl;
newHead->next = *head2;
*head2 = newHead;
cout << "Inside after swap " << (*head2)->value << endl;
}
Why does this one work? Can someone please explain IN DETAIL the pointer magic going on? I have a vague idea but im still a little bit confused. I understand that using a pointer to the head pointer allows you to change the head address globally but it's still a little bit cloudy. Can someone please clarify, what is going on with these pointers in both implementation?
#include <iostream>
using namespace std;
struct Node {
int value = 4;
Node* next;
};
void insertFront(Node*, Node**);
int main(){
Node** head = new Node*;
(*head) = new Node;
(*head)->value = 32;
(*head)->next = nullptr;
cout << (*head)->value << endl;
insertFront(new Node, head);
cout << (*head)->value << endl;
system("pause");
return 0;
}
void insertFront(Node* newHead, Node** head2){
cout << "Inside before swap " << (*head2)->value << endl;
newHead->next = *head2;
*head2 = newHead;
cout << "Inside after swap " << (*head2)->value << endl;
}
Both implementations are using double-indirection wrong, and both leak memory. You're question seems more about double-indirection than just about what works and what doesn't (whether you realize it or not). Its a C question, and though also applicable in C++, it is less so with that language because reference parameters make this somewhat easier (arguably).
I could simply say "use references to pointers" (which you could do), but that would be like you saying "why doesn't my car work?" and me answering "because this car over here will work". So I will provide a C answer (much to the dismay of my own common sense, as I can feel the furnaces firing up from the flamethrowers about to be sent my way). If I have time, I will include the C++ answer (using references), but no guarantees on that.
Pointers to pointers are no different than any other pointer type. All pointer types are types who's variables are defined to "point" to something of that type (I know, its repetitive and trivial, but bear with me here). The trivial example:
void foo(int x)
{
x = 5;
}
obviously doesn't change x on the caller side, and you seem keenly aware of that. If you want to change an in/out parameter using pointers, you need to declare the formal parameter to be a pointer-to type, dereference said-pointer parameter within the function body, and pass the address from the caller. Ie.
void foo(int *p)
{
*p = 5;
}
int main()
{
int x = 0;
foo(&x);
}
The truth is parameters are all pass-by-value in C, even pointer parameters. Yeah, read that again. You say what? Seriously. Its true. It just so happens the "value" you're passing is an address rather than the value within some variable, and in so being as such, the receiver must be something that is prepared to take, and manipulate, data via that address: a pointer.
Now. Pointers to pointers are no different. Pointers to pointers hold addresses of (wait for it...) pointers. Just like our first example, this:
struct Node
{
int data;
struct Node *next;
}
vod foo(Node* ptr)
{
Node *p = new Node();
p->data = 0;
p->next = ptr;
ptr = p;
}
int main()
{
Node *root = nullptr;
foo(root);
}
won't work. You can fix this several ways. One way is using a pointer-to-pointer (the C way). Another uses a reference to pointer (the C++ way).
First the C way, which demonstrates the whole mantra of passing something by address means declaring the parameter to be a pointer-to type (in this case a pointer to pointer type), and passing the address of the thing to modify:
void foo(Node** ptr)
{
Node *p = new Node();
p->data = 0;
p->next = *ptr;
ptr = p;
}
int main()
{
Node *root = nullptr;
foo(&root); // LOOK: passing address of our root pointer
}
Do you see how, just like in our trivial example using int and int*, we have to pass the address of the thing we're modifying to a function that takes a pointer-to-type? In this case the "type" is, itself, a pointer type.
Now, arguable, the C++ way using a reference is trivial by comparison, but IMHO it isn't as clear what is going on, only because there is literally a single character difference between the version that doesn't work and the version that does. Look at this:
vod foo(Node*& ptr) // LOOK added &
{
Node *p = new Node();
p->data = 0;
p->next = ptr;
ptr = p;
}
int main()
{
Node *root = nullptr;
foo(root);
}
Notice how everything else in this is identical to the version that does not work. Everyone has their preferences, and knowing what to look for allows me to use either method, but I can see why some have such difficulty writing and debugging what is essentially double-indirection code hidden in a reference type. Some engineers prefer to send all their out-params as pointer-to types, and I'm generally one of them.
Peeling Back Your Code
After all of that, lets peel back your code and see where things go to hell. I'll dissect the one that does not work, and hopefully you can see why neither version is honestly very good:
First your type:
struct Node
{
int value = 4;
Node* next;
};
Nothing horridly questionable here. The default value assignment in the structure definition. This will puke on non-current-day C++, so likely throw that out for now. If you want a default value, make a constructor (which you should have anyway to ensure all members are properly initialized to something):
struct Node
{
int value;
Node* next;
Node(int val = 4)
: value(val)
, next()
{}
};
Ok. Next up..
void insertFront(Node*, Node**);
You seem to want to use a pure node interface. Most people writing a linked list would do this:
void insertFront(Node** ppRoot, int value);
but we'll go with your version for now. The actual implementation of this:
void insertFront(Node* newHead, Node** head2)
{
newHead->next = *head2;
*head2 = newHead;
}
is correct. Yes it could orphan anything previously being pointed to by newHead->next, but that doesn't seem to be a concern of yours, so we go with it for now.
Finally the torrent: main().
int main()
{
Node head;
head.value = 32;
head.next = nullptr;
Node** headptr = new Node*;
(*headptr) = new Node;
*(*headptr) = head;
(*headptr)->value = 32;//redundant, I know
(*headptr)->next = nullptr;//redundant, I know
cout << head.value << endl;
insertFront(new Node, headptr);
cout << head.value << endl;
system("pause");
return 0;
}
This has multiple issues. First, your mixing dynamic nodes with non-dynamic nodes.
Node head;
head.value = 32;
head.next = nullptr;
Bad idea. This is no reasonable way calling code (in particular cleanup code that deletes each node from the list), has any clue whether something being pointed to is dynamic or not. Don't do that.. Using the constructor version of Node from above, this should simply be:
Node* head = new Node(32);
Next you're dynamically allocating a pointer; (not a Node; a pointer)
Node** headptr = new Node*;
Bad idea. there is no need to do that at all. You already have a pointer variable to your list head (its called, not-coincidentally, head). This appears all to be a setup for invoking the insertion function. To do that, everything from Node** headptr = new Node*; on down can simply be replaced with this:
insertFront(new Node(10), &head); // LOOK: passing address of head pointer
cout << head->value << endl;
The way you are using your pointers is so, so wrong.
Let's look at this code:
Node** headptr = new Node*;
(*headptr) = new Node;
*(*headptr) = head;
(*headptr)->value = 32;//redundant, I know
(*headptr)->next = nullptr;//redundant, I know
cout << head.value << endl;
insertFront(new Node, headptr);
cout << head.value << endl;
Let's first clean up this code a bit. There is no reason to allocate a Node * on the free store (using new), and then reference it through a Node **. It can and should simply be a local variable and referenced directly. To do that, we replace Node** headptr = new Node*; with simply Node *phead, and replace all instances of (*headptr) with merely phead:
Node* phead;
phead= new Node; // #2
*phead= head; // #3
phead->value = 32;//redundant, I know
phead->next = nullptr;//redundant, I know
cout << head.value << endl;
insertFront(new Node, &phead); // here we are passing the address of phead so that insertFront() can modify it
cout << head.value << endl;
Now look at this code carefully. You allocated space for a new Node on line 2, and made phead point to it. You copied the contents of head into this new Node on line 3. Then your insertFront() call modified a newly allocated node and set phead to point to that new node instead. At no point did any pointer ever point to head, and its value is never touched; when you check head.value, of course they remain the same.

Confusion with pointers whilst inserting to the head of a linked list

I'm working through a linked list example. However, I currently cannot understand the head_insert method. Please would someone explain it a little further. Thank you.
#include <iostream>
using namespace std;
struct node_ll
{
int payload;
node_ll* next; // pointer to the next node
};
void head_insert(node_ll** list, int pload)
{
node_ll* temp = new node_ll;//Declare temp, a pointer to a node.
temp->payload = pload;//Set the payload of the struct at the address of temp to pload.
temp->next = *list;//Set the next of the struct at the address of temp to the pointer to the old head of the list.
*list = temp;//Set the pointer to the old head of the list to the pointer to the temp node.
//Why doesnt the temp->next = temp?
};
void print_ll(node_ll** list)
{
node_ll* temp;
temp = *list;
while (temp) // != NULL
{
cout << temp->payload << '\n';
temp = temp->next;
};
}
int main()
{
node_ll* alist = NULL;
cout << "Empty list a to start\n";
head_insert(&alist, 2);
head_insert(&alist, 4);
head_insert(&alist, 6);
cout << "List a after head insertion of 2,4,6 is \n";
print_ll(&alist);
cout << '\n';
system("PAUSE");
return 0;
}
My confusion is detailed in the comments. If I have the lines
temp->next = *list;
*list = temp;
why doesn't my newly created node point to its own address in next?
//Declare temp, a pointer to a node.
No. "Create a new node, and let temp be the address of that node."
//Set the payload of the struct at the address of temp to pload.
No. "Set the payload of the struct whose address is temp to pload". That's probably what you meant, but you really need to be precise about these things. Anyway, this is filling in the payload of the new node that we just created.
//Set the next of the struct at the address of temp to the pointer to the old head of the list.
Similarly... "Set the next of the struct whose address is temp to the address of the old head of the list."
//Set the pointer to the old head of the list to the pointer to the temp node.
Careful. Here's the thing: "the address of the old head of the list" is a value, not a variable. It can exist at multiple places in memory, in the same way that the number 4 can be stored at multiple places in memory.
The function was given a node_ll**, i.e. a (node_ll*)* - a pointer to a node_ll*. Specifically, when we called the function from main, we gave it a pointer to the variable a_list in the current call to main.
Thus, when we do *list =, we are writing to that memory location - in effect, replacing the a_list variable. Playing with memory addresses like this allows us to simulate "pass by reference" and change the value of variables that come from the caller (we can't just access these from the parameters, because we were given a copy; and we can't access them as globals because they aren't globals).
//Why doesnt the temp->next = temp?
Why would it? Code runs from top to bottom (control structures notwithstanding). temp->next was set to the old head of the list, before we set the new head of the list.
It seems like you expected temp->next to change simply because, at that point in the process, it happened to point to the old head of the list, and then we changed a variable that also happened to have the same value - i.e., to point to the old head of the list. But they are quite clearly separate variables. If I write a = 4; a *= 3, the value 4 does not change; the variable a does. So it is with pointers, as well; they're just another kind of value.
This is confusing code.
list is a pointer to a pointer to a node. *list = temp is not changing any nodes, it's changing the pointer that was passed in, so it points to the inserted node.
In your head_insert function new Node is added to the beginning. ie new new node will be the head of your linked list
temp->next = *list;//Store pointer to earlier head as the next node
*list = temp; // Make pointer new node as the head node
In your Code a double pointer is passed as argument into the function.
ie if A is your pointer header node then an address B which contains A is passed as argument into your function.