Printed out the address of head and &head:
head:0x603050
&head :0x7fffffffe4b8: what does this signify?
void push(node* &head,int key)// Inserts items at front of link list
{
node* linkNode=new node(); //declares new node
linkNode->data=key;
if(head==NULL) //if the link list is empty then create a new one.
{
linkNode->next=NULL;
head=linkNode; //1
}
else
{
linkNode->next=head;
head=linkNode;
}
}
Main function where all other functions are called from
link list is 8,4,2
main function
int main(int argc, char** argv)
{
node* head=NULL; //initializing head to NULL
push(head,2); //creating link list
push(head,4); //this requires &head
push(head,8); //link list is 8,4,2
selectSort(head); //this does not require &head
reverse(head); //this requires &head
return 0;
}
Why do we need to pass it by reference of reference such as in push(node* &head, int key)
Otherwise it won't work to set the given linkNode as current head:
if(head==NULL) //if the link list is empty then create a new one.
{
linkNode->next=NULL;
head=linkNode; // <- This statement changes the head variable passed from main()
}
What you have is a reference to a pointer (head) that will be 'returned' from the push() function, and set the head pointer passed from the caller correctly:
node* head=NULL;
push(head,2); // sets head to the node created for key '2'
Don't forget to delete all the node instances you have created with new node();. In a different context as you're showing, this might lead to memory leaks.
That's not a "reference of reference"; it's a reference to a pointer.
It means that, once the pointer head has been set to point to the new element, within the function, this change also affects the pointer you originally passed in to the function.
selectSort(head); //this does not require &head
It probably should do, actually, if the function performs a sort over all elements of the list.
reverse(head); //this requires &head
After this call, head now points to the new head of the list. This would not be possible if you'd passed head by value.
An alternative implementation might return the new head pointer, instead of using this "out parameter" convention.
The reason you must pass head to the push function is because your push function is expecting to modify the value of the head pointer. If you don't pass it by reference, any changes to it will only be available within the function call. For example, if it was not passed by reference, and you passed head (initialized to NULL), to the push function, a new item would be created, but your value for head would only be updated inside the function. Once you left the function, it will still be NULL (because you passed the pointer by copy).
Note that this can go away if you create a linked list class instead of treating your nodes as a linked list themselves (that is, encapsulate the nodes under a list interface - which is what the standard library does).
Related
Hey Guys my code is supposed to create a linked list of students and for each student, it has to create a linked list of grades for that student. I cant really tell if my two linked lists are set up properly, since no grades print when i try to traverse thru the lists.
struct Grade{
float score;
};
struct GradeNode{
Grade grade;
GradeNode *next_gnode;
};
struct StudentNode {
string name;
GradeNode *ghead;
StudentNode *next_snode;
};
StudentNode* head; //head of student linked list
the function below takes input from a file and makes a node with its value along with a pointer (ghead) to a linked list of grades, Set to null at first.
void buildStudentList(string n){
StudentNode *newNode{ new StudentNode}; //initialize new Student node
StudentNode *curr; //to traverse thru Student lIst
//initialize student node
newNode->name = n;
newNode->next_snode = nullptr;
//have HEAD of THIS student's grades set to null, since there are no grades present for this student at this moment
newNode->ghead = nullptr;
//if student list is empty
if(!head){
//make this student node the head of the list
head = newNode;
}
else{
//else add it to the end of the list
curr = head;
//traverse to the end of the list
while(curr->next_snode){
curr= curr->next_snode;
}
//make grades for this student
buildGradeList(newNode->ghead, newNode->name);
//assign new node to the end of the list
curr->next_snode = newNode;
}
};
build grade list function
//parameter is Grade Head, where we will attach a grade link list to it
void buildGradeList(GradeNode *head, string n){
//NOTE: head is HEAD OF GRADE LIST
bool quit = false;
int x;
while (!quit) {
cout<<"ENTER GRADE FOR "<<n<< ": (0 to quit)"<<endl;
cin>>x;
cout<<endl;
if(x==0){
//exit while loop and return //when one presses 0, they go to the next student on the list!!!
quit=true;
}
else{
//append this value to head
appendGrades(head, x);
}
}
//return to prev function
return;
}
appends grade to linked list, head is still ghead (head of grade list for this student)
void appendGrades(GradeNode *head, int s){
//create a new node with new score value
GradeNode *new_grade = {new GradeNode};
new_grade->grade.score = s;
new_grade->next_gnode = nullptr;
//node to traverse list
GradeNode *curr;
if(!head){
head = new_grade;
}else{
curr=head;
while (curr->next_gnode) {
curr= curr->next_gnode;
}
curr->next_gnode = new_grade;
}
};
Would appreciate any input, guys!
The easiest solution to implement would be to change GradeNode * head to GradeNode *& head in the signature for buildGradeList and appendGrades functions. This will work, but I don't suggest you use it, because it misses the point of your exercise.
Your code seems mostly correct to me (I haven't run it, so I can't be sure,) apart from the one problem: when you pass the head of the grades list to those two functions, you pass it by value. This means that a copy is made of the head, and all your changes will be made to a copy, which means they don't take effect and your students' GradeNode * gheads will never actually point to anything.
Based on the mostly-correct code you have here (and based on my experience that most programmers struggle with pointers and linked lists,) I think you understand the concept of passing something by value versus passing a pointer/reference to something. However, to be able to work with pointers, you have to understand that a pointer itself is nothing but an address, i.e. a value. Therefore, when you pass a pointer into a function, you can modify the value of the object that it points to and that change will be seen by the caller, but any change you make to the pointer itself will be lost at the end of the function, because these changes were made to a copy of an address which means you don't have access to - and therefore cannot change - the original address.
This all means that when passing a pointer to a function, you cannot change where it points to. But the solution is easy.
When you want to change the value of an int variable inside a function and have the caller see the change, you pass the address of that integer to the function, in the form of an int *. So, if you want to change the value of an 'int *' variable inside a function (not the value it points to, but the value of the pointer itself,) you pass the address of that pointer to the function, in the form of an int **.
In your case, that means you have to change the signature of the two functions I mentions to these:
void buildGradeList(GradeNode **head, string n);
void appendGrades(GradeNode **head, int s);
and of course, you have to make slight modifications to the body of appendGrade as well:
...
if(!*head){
*head = new_grade;
}else{
curr=*head;
...
This will be correct, and this will work, and it will be right in the spirit of the original problem and your solution.
The solution I suggested at the top also works, with no change other that adding an & (called a "reference", or a little more precisely an "lvalue reference") to the function signatures because that is exactly what a "reference" is in C++. A reference is a pointer that doesn't need special syntax to work with (no * to de-reference or & to take the address of something.) This means that references are more convenient to work with, but they can't do many of the things that you do with pointers (e.g. the loop you have to find the end of the linked list is impossible to write in that form using references.)
But I want to suggest something even better. Both functions that take the head of the grades list might also change that list. So I suggest that instead of accepting a pointer to a pointer to the head of the list (or a reference to a pointer to the head,) they can always return the pointer to the head. This means that they sometimes return a new head pointer, and sometimes the same pointer that was passed to them, but they don't change the actual head pointer themselves; they return the pointer they think should be the head, and let whoever called them to decide.
The changes you need to make are as follows:
// First, change how we call buildGradeList inside buildStudentList:
newNode->ghead = buildGradeList(newNode->ghead, newNode->name);
// then, change the signature for buildGradeList:
GradeNode * buildGradeList (GradeNode * head, string n) {
// then, when you are calling appendGrades, store the value it returns in "head":
head = appendGrades(head, x);
// appendGrades will return the "head" (sometimes new, sometimes the same old one)
GradeNode * appendGrades (GradeNode *head, int s){
// just add this to the end of the appendGrades function:
return head;
That's it. You could also change the buildStudentList function to obey this design and always return the head of the students linked list (sometimes new, sometimes the same old one.) I believe this is better and more useful, specially in more complex problems/tasks you will encounter later.
This bit of code inserts at the tail of a linked list and it works perfectly when the head node is not null, i.e. it already points to some linked list.
void Insert(node *head,int x)
{
if (head==NULL)
{
head=new node;
head->key=x;
head->next=NULL;
}
else
{
link=head;
while (link->next!=NULL)
{
link=link->next;
}
link->next=new node;
link->next->key=x;
link->next->next=NULL;
}
}
For the first part of the code, if the head node is Null, which it initially is, I simply put in the data and pointer in the node.
When its not null, the 'link' node begins at the head of the list and traverses till the tail, therein I put in the node.
This bit of code below, which only takes one function works in all cases. Why is that? head is equal to NULL and globally defined in both cases.
void insert(int x)
{
if (head==NULL)
{
head=new node;
head->key=x;
head->next=NULL;
}
else
{
link=head;
while (link->next!=NULL)
{
link=link->next;
}
link->next=new node;
link->next->key=x;
link->next->next=NULL;
}
}
Note: This is not an assignment or homework or anything related. I am just trying to learn basic stuff regarding linked lists and this is a problem i came across while doing some stuff on Hacker Rank.
In case anyone's interested in the display function:
void display()
{
node *trav=head;
while (trav!=NULL)
{
cout<<trav->key;
trav=trav->next;
}
}
Struct has been defined in my program.
struct node
{
int key;
node *next;
}
For the sake of convenience, I have defined head pointer globally, but with some slight adjustments i could change that. I think. Also 'link' is also global in case anyone's confused where it came from.
node *head = NULL;
node *link = NULL;
So to summarize, the question is :
Why does it work in one argument but not for the two arguments version when head is NULL.
In the first function, where you pass head as an argument, you pass the argument by value. That means inside the function head is a copy of the value you pass when calling the function, and modifying a copy will not modify the original.
You need to pass the argument by reference, which is easily done in C++ using the ampersand (&) when declaring the argument:
void Insert(node *& head,int x) { ... }
// ^
// Note ampersand here
That tells the compiler that head is a reference to the original variable you use when you call the function.
Printed out the address of head and &head:
head:0x603050
&head :0x7fffffffe4b8: what does this signify?
void push(node* &head,int key)// Inserts items at front of link list
{
node* linkNode=new node(); //declares new node
linkNode->data=key;
if(head==NULL) //if the link list is empty then create a new one.
{
linkNode->next=NULL;
head=linkNode; //1
}
else
{
linkNode->next=head;
head=linkNode;
}
}
Main function where all other functions are called from
link list is 8,4,2
main function
int main(int argc, char** argv)
{
node* head=NULL; //initializing head to NULL
push(head,2); //creating link list
push(head,4); //this requires &head
push(head,8); //link list is 8,4,2
selectSort(head); //this does not require &head
reverse(head); //this requires &head
return 0;
}
Why do we need to pass it by reference of reference such as in push(node* &head, int key)
Otherwise it won't work to set the given linkNode as current head:
if(head==NULL) //if the link list is empty then create a new one.
{
linkNode->next=NULL;
head=linkNode; // <- This statement changes the head variable passed from main()
}
What you have is a reference to a pointer (head) that will be 'returned' from the push() function, and set the head pointer passed from the caller correctly:
node* head=NULL;
push(head,2); // sets head to the node created for key '2'
Don't forget to delete all the node instances you have created with new node();. In a different context as you're showing, this might lead to memory leaks.
That's not a "reference of reference"; it's a reference to a pointer.
It means that, once the pointer head has been set to point to the new element, within the function, this change also affects the pointer you originally passed in to the function.
selectSort(head); //this does not require &head
It probably should do, actually, if the function performs a sort over all elements of the list.
reverse(head); //this requires &head
After this call, head now points to the new head of the list. This would not be possible if you'd passed head by value.
An alternative implementation might return the new head pointer, instead of using this "out parameter" convention.
The reason you must pass head to the push function is because your push function is expecting to modify the value of the head pointer. If you don't pass it by reference, any changes to it will only be available within the function call. For example, if it was not passed by reference, and you passed head (initialized to NULL), to the push function, a new item would be created, but your value for head would only be updated inside the function. Once you left the function, it will still be NULL (because you passed the pointer by copy).
Note that this can go away if you create a linked list class instead of treating your nodes as a linked list themselves (that is, encapsulate the nodes under a list interface - which is what the standard library does).
I am trying to implement a Linked ArrayList in C++ for instruction purposes, I've hit a snag though and I'm unsure how to unsnag it. My pointer array doesn't seem to be composed of pointers, but of actual objects.
Keeping my code as brief as possible.
//arraylist.h//
class classArrayList {
private:
class Node {
Node();
//accessors
};
Node* classArray;
public:
classArrayList();
};
//arraylist.cpp//
classArrayList::classArrayList() {
Node* node = new Node();
this->setHead(node);
this->setMaxSize(5);
classArray = new Node[5];
this->classArray[0] = *node;
this->setSize(1);
}
void classArrayList::deleteNode( int index ) {
Node* my_current = &this->classArray[index];
//blahblah
}
But when I go to delete a node, "my_current" doesn't link to whatever would be next or prev in this list. Trying to delete at position zero, no next.
So there's definately a node with data but it doesn't have its links, but checking the debugger my linked list is fine and works, so its whatever the array is pointing to that's screwing up.
So instead of pointing to the list, its pointing to unique instances, how can I fix this?
My code to add something new to the array is: this->classArray[some_index] = *new_node;
To clarify, I wanna be able to have an array that points sequencially to each object in my linked list. And then when I ask for one at any n in my arraylist, reference it to a pointer and then do thins to the object in my list through its position in the array, rather than increment through the list until I find the nth one I want.
Make your classArray a double pointer and create a Node pointer array. Node* classArray; Copy the address of head of your list to each array.
classArray = new Node*[5];
In your code by your statement this->classArray[0] = *node; you are not storing the address of the newly created, instead content of newly created node. And by deleting you are not removing the dynamically created list head.
For copying the address of newly created list you should use
this->classArray[0] = node;
The code works as it should. When you delete a node from your linked list, you delete the data under the pointer. As you set my_current to the address of the deleted node, you actually don't point to anything. The problem doesn't lie in the code, but in your understanding of the subject.
In order to really make a working linked list, every node should consist of a pointer to the next node. That way, when you delete a node, you'll first be able to retrieve the next node from the pointer, and set your my_current to a valid address.
In order to solve your problem, you should actually read a bit about the subject.
If you want to access the elements in "array style", overload the operator [].
Node& classArrayList::operator [](unsigned int index)
{
Node *node = head;
for(unsigned int i=0;i<index;i++)
if(node->next()) node = node->next();
else break;
return *node;
}
This is a noobie question, but I'm not sure how to pass by reference in C++. I have the following class which sets up a Node and a few functions.
class Node
{
public:
Node *next;
int data;
Node(int dat)
{
next = NULL;
data = dat;
}
Node* getNext()
{ return next; }
void setNext(Node *n)
{ next = n;}
void reverse(Node *root)
{
Node *previous = NULL;
while(root != NULL)
{
Node *next = root->getNext();
root->setNext(previous);
previous = root;
root = next;
}
root = previous;
}
};
Now, the purpose of my little class is to create a singularly linked list and have the ability to reverse it. And it seems to work fine, if I return the node named 'previous' at the end of reverse.
But look at my main function:
int main()
{
Node *root = new Node(1);
Node *num2 = new Node(2);
Node *num3 = new Node(3);
Node *num4 = new Node(4);
root->setNext(num2);
num2->setNext(num3);
num3->setNext(num4);
root->printList();
root->reverse(root);
root->printList();
return 0;
}
printList() was omitted for sake of space, but it just prints a list given a node. The problem is, when root->reverse(root) is called, root doesn't actually end up pointing to 'previous'.
The output would be this:
1
2
3
4
// the value of previous from the reverse function is 4
1
I really don't understand the output. Anyone care to explain what's happening? (Why isn't the list reversed even though if I did something like this root = root->reverse(root) where reverse returns previous, it would) why is it that root now only points to itself? I'm new to c++ and appreciate your help!
C++ has support for reference semantics. Therefore, for a given function:
void foo(Bar& bar);
To pass by reference you do:
int main() {
Bar whatsit;
foo(whatsit);
return 0;
}
That's it!
This is commonly confused with passing a pointer, where for a function such as:
void foo(Bar* bar);
You would do:
int main() {
Bar whatisit;
foo(&whatsit);
return 0;
}
The difference is mostly a matter of semantics:
- A reference is always valid. There is no reason to check for a NULL pointer.
- A pointer could be NULL, and as such, should be checked.
It is, however, possible for a reference to refer to a NULL pointer, however, if the programmer decides to be evil and abuse reference semantics, but the principle remains.
You aren't passing by reference. You are passing a copy of the pointer. This copy still points to the same node, but it is still just a copy with local scope. Basically it is another pointer pointing to the node that the pointer in main is pointing to (ha!). At the end of your function, your assignment is assigning previous to this pointer copy, and then the function ends and the copy goes out of scope. Your pointer in main remains unchanged.
The reason returning/assigning the pointer worked is that this copy which has been set to what you want is returned and assigned to your pointer in main.
You can fix this in a multitude of ways. Pass a reference to your pointer (ugly imo), use references, or return root and do an assignment.
To pass a pointer by reference you can declare reverse as:
void reverse(Node*& root) {
// ...
}