Difference between Node->next!=NULL and Node!=NULL in C - c

This function doesn't work if I make a modification in while condition and change temp != NULL to temp->next = NULL. Why is that?
void Print() {
printf("\n");
printf("The Library data is as follows: \n");
struct Node *temp = head; // where head is a global variable
printf("\n");
while (temp != NULL) {
printf("%25s", temp->name);
printf("%25s", temp->author);
temp = temp->next;
printf("\n");
}
}
Plus if I modify the while loop condition under else block, from temp1->next = NULL to temp1 != NULL, it doesn't work. Why is that?
void Insert(char q[50], char r[50]) {
struct Node *temp = (struct Node*)malloc(sizeof(struct Node));
temp->next = NULL; // Since we are adding a node to the end, we are linking it to NULL.
strcpy(temp->name, q); // copying the contents of "q" to "temp->name"
strcpy(temp->author, r); // same
if (head == NULL) {
head = temp;
} else {
struct Node *temp1 = head;
while (temp1->next != NULL)
temp1 = temp1->next;
temp1->next = temp;
}
}

In the Print function, you want to enumerate all nodes in the list, and you want to handle an empty list (head = NULL) gracefully. Hence the loop iterates while (temp == NULL) and temp skips to the next node with temp = temp->next;.
In the Insert function, a new node is allocated and initialized. There is a special case for the empty list (head == NULL) where head just receives the pointer to the new node. Conversely, if the list is not empty, you want to find the last node of the list to append the new node by setting its next pointer to point to the new node. The loop iterates from the first to the last node, the test temp1->next != NULL succeeds if the node is not the last one. Hence temp points to the last node after the while loop and the new node can simply be appended with temp1->next = temp;.
Note the following remarks:
the prototype void Insert(char q[50], char r[50]) should be improved as int Insert(const char *name, const char *author) because:
the strings passed as arguments are not modified by the function
the argument names would be clearer
the array sizes specified are ignored by the compiler and seem inconsistent with the actual structure members.
the function can fail. It should at least return a success indicator.
memory allocation should be tested for success and failure should be reported
strcpy will cause undefined behavior if the arguments strings are too long.
There is no need to cast the return value of malloc in C.
Here is an improved version:
#include <stdio.h>
#include <stdlib.h>
struct Node {
char name[50];
char author[50];
struct Node *next;
};
struct Node *head = NULL;
void Print(void) {
printf("\nThe Library data is as follows:\n\n");
struct Node *temp = head; // where head is a global variable
while (temp != NULL) {
printf("%25s %-25s\n", temp->name, temp->author);
temp = temp->next;
}
}
int Insert(const char *name, const char *author) {
struct Node *temp = malloc(sizeof(struct Node));
if (temp == NULL)
return -1;
temp->next = NULL;
snprintf(temp->name, sizeof(temp->name), "%s", name);
snprintf(temp->author, sizeof(temp->author), "%s", author);
if (head == NULL) {
head = temp;
} else {
struct Node *temp1 = head;
while (temp1->next != NULL)
temp1 = temp1->next;
temp1->next = temp;
}
return 0;
}
int main() {
if (Insert("Flowers for Algernon", "Daniel Keyes")
|| Insert("Blade Runner", "Philip K. Dick")
|| Insert("2001, a Space Odyssey", "Arthur C. Clarke")) {
printf("out of memory\n");
return 1;
}
Print();
return 0;
}

When change that to node->next in while loop its mean this loop loops while node->next is null so u miss last node of your linked array because this node's-next is null so loop is break in this time.And only write temp to your while u dont need temp != NULL this loop breaks when temp is null so only put
while(temp){
//your code
}
I hope this will be help you. :-)

In the first case You are traversing through the entire linked list.End of linked list is denoted by NULL pointer as per your code so while(temp!=NULL) is used.This will work with temp1->next!=NULL if there are more than 2 nodes by skipping the last one.
In second case you add new node to the end of the last node.So you have to use temp1->next!=NULL. so that the last node's next pointer can point to the newly added node.If you use temp!=NULL in this case, Then temp becomes NULL. So the next statement temp1->next=temp; cannot work.
If you make change in first case, it will only cause program to skip
printing the last node in the linked list.
If you make change in second case, this will cause your code to get
terminated (runtime error).

Its very simple
In function print() when you use while(temp->next!=null) then it will not print last
node because when pointer temp is at last node temp->next is null and while condition
become false and it come out of while loop.
In function insert() if you change while(temp1->next!=NULL) to while(temp1!=NULL) then
when it come from while loop temp1 points to null means no memory is allocated .
hence writing temp1->next in after while loop shows error as you cannot excess next
part of temp because memory is not allocated.
Hope this will help you!

Related

This code works great for almost every testcase except when the element to be deleted is the 2nd last element from the end of the list

The program is for deleting a node from a double linked list and printing out the new list
The code works great for almost every testcase except when the element to be deleted is the 2nd last element from the end of the list.
When that is given I get a segmentation fault error in my delete function, which i just have not been able to fix and hope to get fixed.
#include <stdio.h>
#include <stdlib.h>
//no work
struct node{
int data;
struct node *next;
struct node *prev;
};
struct node *head = NULL;
void display();
void addnode(int x){
struct node *current = (struct node *)malloc(sizeof(struct node));
current->data = x;
current->next = NULL;
current->prev = NULL;
if (head == NULL)
head = current;
else{
struct node *temp;
for (temp = head; temp->next != NULL; temp = temp->next);
temp->next = current;
current->prev = temp;
}
}
void delete(int t){
struct node *temp;
if (head->next == NULL){
if (head->data != t)
printf("Target Element is Not Found\n");
else{
display();
printf("List is Empty\n");
}
}else{
for (temp = head; temp->next != NULL && temp->data != t; temp = temp->next);
if (temp->data == t){
if (temp->next != NULL){
temp->next->next->prev = temp;
temp->next = temp->next->next;
}
}
}
}
void display(){
struct node *temp;
printf("List->");
for (temp = head; temp->next != NULL; temp = temp->next)
printf("%d ", temp->data);
printf("%d->NULL\n", temp->data);
}
int main(){
int n, temp;
scanf("%d", &n);
while (n--){
scanf("%d", &temp);
addnode(temp);
}
int t;
scanf("%d", &t);
display();
delete(t);
display();
}
There seem to be some world limit for this so let me try to fill that up very quick. Cuz i really want to earn some reputation and finally ask a whole bunch of stuff i wanted to ask.
[1]: https://i.stack.imgur.com/Nke8q.png
When temp points to the node to be deleted, and it is the next-to-last, then temp->next is not null but temp->next->next is, and your code attempts to execute temp->next->next->prev = temp;. Since temp->next->next is null, using temp->next->next->prev does not work. You need to rethink what your code is doing and why.
The code works great for almost every testcase except when the element to be deleted is the 2nd last element from the end of the list.
I don't agree and below is the reason:
Multiple problems in your delete() function.
Major (you are already aware of this): If the list has more than 1 elements in it and, for deletion, user entered second last node to delete then segmentation fault is occurring. Its because of this in delete():
temp->next->next->prev = temp;
temp->next->next is NULL and your code is attempting to access NULL pointer.
Major: If the list contain only one element and if you give that element as input to delete, it will output - List is Empty and node with that value will not be deleted:
if (head->next == NULL){
if (head->data != t)
printf("Target Element is Not Found\n");
else{
display();
printf("List is Empty\n");
}
....
....
Major: If the list has more than 1 elements in it and, for deletion, user entered any node to delete other than last and second last node, the delete() will end up deleting the node next to the node entered by user (which is supposed to be delete). Moreover, there is memory leak in this scenario.
if (temp->data == t){
if (temp->next != NULL){
temp->next->next->prev = temp;
temp->next = temp->next->next;
}
....
....
All statements are making changes in temp->next pointer and not in temp pointer. Also, deleted node memory is not freed up anywhere.
Major: If the list has more than 1 elements in it and, for deletion, user entered last node, no deletion will happen and the last node will remain part of list. Its because of this in delele():
if (temp->data == t){
if (temp->next != NULL){
If temp is pointing to last node then temp->next will be NULL.
Minor: If the list has more than 1 elements in it and, for deletion, user entered some node which does not exists in the list than no output message to inform this to the user.
Problem in display() function:
Major: Pass NULL to display() function and it will give segmentation fault. This will be the case when your list will have only one element and that element will be deleted then the list will be empty and when display() will be called after delete(), it will result in segmentation fault. It's because of this in display():
for (temp = head; temp->next != NULL; temp = temp->next)
^^^^^^^^^^
If temp is NULL then it will attempt to access NULL pointer which is UB.
To delete a node in doubly linked list, you need to take care of it's previous and next pointer. The next of previous should be reset to its next node and previous of next should be reset to its previous node. If its previous is NULL that means its first node of the list and, in this case, reset the head of list to pointing to its next node.
Implementation:
void delete (int t) {
struct node *temp;
for (temp = head; temp != NULL && temp->data != t; temp = temp->next);
if (temp == NULL) {
printf("Target Element is Not Found\n");
return;
}
if (temp->prev != NULL) {
temp->prev->next = temp->next;
temp->prev = NULL;
}
else {
head = temp->next;
}
if (temp->next != NULL) {
temp->next->prev = temp->prev;
temp->next = NULL;
}
free (temp);
}
Need to fix the display as well. It should be like this:
void display (void) {
struct node *temp;
printf("List->");
for (temp = head; temp != NULL; temp = temp->next)
printf("%d ", temp->data);
printf ("\n");
}
To delete the element pointed to by cur, you need to redirect the pointer next of the previous and the pointer pred of the following, provided these elements exist. Get these elements with
node* pred= cur->pred, * next= cur->next;
Now shunt
(pred ? pred->next : head)= next;
(next ? next->pred : tail)= pred;
and release the current element:
delete cur;

create linked list using char array as data

I am having a problem on assigning char array after I create a node.
I am having trouble on this function I created which it would make a new node and then assign character array into the created node. I don't have any problems when it comes to int but I can't seem to run when I switched to character array.
I get a run time error when I try to run my code.
Any help would be much appreciated.
Thank You!
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX 100
struct node{
char data[MAX];
struct node *next;
};
typedef struct node* nodePtr;
void create(nodePtr head, char data[]);
int main()
{
nodePtr head = NULL;
char str[] = "HELLO";
create(head, str);
return 0;
}
void create(nodePtr head, char data[])
{
if (head == NULL)
{
// empty list
head = (nodePtr) malloc(sizeof(struct node)); // create root
strcpy(head->data, data);
head->next = NULL;
}
else
{ // list not empty
nodePtr current = head; // start at the beginning...
while (current->next != NULL)
{
current = current->next; // walk to the end of the list
}
current->next = (nodePtr) malloc(sizeof(struct node));
current = current->next;
strcpy(current->data, data);
}
}
There is more than one problem with your program.
To begin with, when you add elements to a list that already has a head, are not initializing the next member. This will cause multiple list insertions to fail.
current->next = malloc(sizeof(struct node));
current = current->next;
strcpy(current->data, data);
current->next = NULL; //<-- you forgot this
The other big issue is that you are also leaking your entire list, because you pass the head pointer by value into the function. When the list is empty, the function modifies this value but it's a copy so when the function returns, the value of head in main is still NULL.
There are two options. Either you change your function to expect a pointer to the head-pointer, or you use what's called a "dummy head".
Using a dummy head actually simplifies lists a lot. What this means is your head is actually an unused node whose sole responsibility is to store the actual head in its next-pointer:
struct node head = {}; // dummy head node
create(&head, str);
The above will never actually hit the head == NULL part of the create function because dummy heads guarantee the head is always a valid node. So if you set your list up that way, then your create function can be simplified.
If you don't want to do this, then you need to pass a pointer to your head pointer. That means your create function becomes:
void create(nodePtr *head, char data[])
{
if (*head == NULL)
{
*head = malloc(sizeof(struct node));
strcpy((*head)->data, data);
(*head)->next = NULL;
}
else
{
nodePtr current = *head;
while (current->next != NULL) current = current->next;
current->next = malloc(sizeof(struct node));
current = current->next;
if (current != NULL)
{
strcpy(current->data, data);
current->next = NULL;
}
}
}
And you would invoke the above as:
nodePtr head = NULL;
create(&head, str);
One extra thing you might wish to do is make the function return the node that it created. The reason you might want to do this is that currently if you're inserting many items into the list you have to search to the end every time. If instead you pass the last node as the next head, then no searching is necessary:
nodePtr head = NULL;
nodePtr tail = head;
tail = create(head, "goodbye");
tail = create(tail, "cruel");
tail = create(tail, "world");
This would mean a small modification to your function, but I'm sure you can work that out.

Linked List Reversal has errors

In our class right now we're covering nodes and linked lists, and are working on our first linked list program.
We've been given the following guidelines by the teacher:
Make sure your main function will accept 10 characters from STDIN and create a linked list with those characters (so your nodes will have a char member). Then, add an additional function called reverse. The purpose of the reverse function will be to create a copy of the linked list with the nodes reversed. Finally, print off the original linked list as well as the reversed linked list.
I've gotten it all written out, and I've compiled it with no errors - but the program doesn't work as intended, and I'm not entirely sure why. I'm sure it has something to do with how I've set up the pointers to "walk" the nodes - as the debug I put in shows it looping twice per user input letter. Specifications are that we're only supposed to use one function, and we pass a Node* to the function, and it returns the same. The function cannot print out anything - only make the second list that is a reverse of the first.
Any help would be greatly appreciated, I'm not terribly good at this yet and I'm sure I've made some rather silly mistakes.
#include <stdio.h>
#include <stdlib.h>
//struct declaration with self-reference to make a linked list
struct charNode {
char data;
struct charNode *nextPtr;
struct prevNode *prevPtr;
};
typedef struct charNode Node; //makes Node an alias for charNode
typedef Node *NodePtr; //makes NodePtr an alias for a pointer to Node (I think?)
//function declaration for a reverse function
Node* reverse(Node *stPtr);
int main(void)
{
//main function takes 10 letters and puts them in a linked list
//after that, it calls the reverse function to create a reversed list of those characters
//lastly it prints both lists
NodePtr newNode = NULL;
char input;
Node* revStart;
unsigned int counter = 0;
printf("Enter 10 letters to make a list: ");
NodePtr currentPtr = NULL; //sets currentPointer to startNode.
NodePtr previousPtr = NULL; //set previousPointer to null to start
while(counter<= 10)
{
scanf("%c", &input); //gather next letter
NodePtr newNode = malloc(sizeof(Node)); //creates a new node
if (newNode != NULL) //checks to make sure the node was allocated correctly
{
newNode->data = input; //makes the new node's data == input
newNode->nextPtr = NULL; //makes the nextPtr of the newNode NULL
}
currentPtr = newNode; //sets currentPtr to the address of the newNode
if(previousPtr == NULL) { //first time around previousPtr == NULL
newNode->nextPtr = newNode;
previousPtr = newNode; //sets previousPtr to the address of the new node (1st time only)
} else { //afterwards, currentPtr won't be NULL
previousPtr->nextPtr = currentPtr; //last node's pointer points to the current node
previousPtr = newNode; //update previous pointer to the current node
}
++counter;
//debug
printf("\nLoop #%d\n", counter);
}
revStart = reverse(newNode);
puts("The list is: ");
while (newNode != NULL){
printf("%c --> ", newNode->data);
currentPtr = currentPtr->nextPtr;
}
puts("NULL\n");
}
//reversing the nodes
Node* reverse(Node *stPtr)
{
//make a new node
NodePtr currentPtr = stPtr->nextPtr; //get the next letter ready (this will point to #2)
NodePtr prevRevPtr = NULL; //previous reverse node pointer
Node* revStart;
for(unsigned int counter = 1; counter <= 10; ++counter)
{
NodePtr revNode = malloc(sizeof(Node));
if(revNode != NULL) //if reverseNode is allocated...
{
if(prevRevPtr = NULL) //if previousReversePointer = NULL it's the "first" letter
{
revNode->data = stPtr->data; //letter = current letter
revNode->nextPtr = NULL; //this is the "last" letter, so NULL terminate
prevRevPtr = revNode; //previousReversePointer is this one
}else //after the first loop, the previous ReversePointer will be set
{
revNode->data = currentPtr->data; //set it's data to the pointer's data
revNode->nextPtr = prevRevPtr; //reverseNode's pointer points to last node entered
currentPtr = currentPtr->nextPtr; //moves to next letter
prevRevPtr = revNode; //changes previous reverse node to current node
if(counter == 10)//on the last loop...
{
revStart = revNode; //set revStart as a pointer to the last reverse node
//which is technically the "first"
}
}
}
}
return revStart;
}
Assuming your list is properly wired from inception, reversing a double-linked list is basically this:
Node *reverse(Node *stPtr)
{
Node *lst = stPtr, *cur = stPtr;
while (cur)
{
Node *tmp = cur->nextPtr;
cur->nextPtr = cur->prevPtr;
cur->prevPtr = tmp;
lst = cur;
cur = tmp;
}
return lst;
}
That's it . All this does is walk the list, swapping pointers, and retaining whatever the last node processed was. When done correctly the list will still be end-terminated (first node 'prev' is null, last node 'next' is null, and properly wired between.
I strongly advise walking a list enumeration through this function in a debugger. With each iteration watch what happens to cur as it marches down the list, to the active node's nextPtr and prevPtr values as their swapped, and to lst, which always retains the last-node processed. It's the new list head when done.
Okay so we don't need to contend with no line breaks in commments:
Node *reverse(Node *list) {
Node *rev = NULL;
while (list) {
Node *elt = list; // pop from the list
list = list->next;
elt->next = rev; // push onto reversed list.
rev = elt;
}
return rev;
}
As you wrote in comments, you probably don't need to have a previous pointer; you can just create a singly linked list.
There are several issues in your code, including:
When malloc returns NULL, you still continue with the loop -- only part of the code is protected by the if that follows, but not the rest. You should probably just exit the program when this happens.
Your algorithm does not maintain a reference to the very first node, i.e. the place where the linked list starts. When you print the list you should start with the first node of the list, but instead you start with newNode, which is the last node you created, so obviously not much will be printed except that last node. Moreover, both other pointers you have, will also point to the last node (currentPtr, previousPtr) when the loop ends.
newNode->nextPtr = newNode; temporarily creates an infinite cycle in your list. This is resolved in the next iteration of the loop, but it is unnecessary to ever make the list cyclic.
In the reverse function you have if(prevRevPtr = NULL)... You should get a warning about that, because that is an assignment, not a comparison.
Some other remarks:
The reverse function unnecessarily makes distinction between dealing with the first node and the other nodes.
It is also not nice that it expects the list to have 10 nodes. It would be better to just rely on the fact that the last node will have a NULL for its nextPtr.
It is a common habit to call the first node of a linked list, its head. So naming your variables like that is good practice.
As you are required to print both the initial list and the reversed list, it would be good to create a function that will print a list.
As you need to create new nodes both for the initial list and for the reversed list, it would be good to create a function that will create a node for you.
(I know that your teacher asked to create only one function, but this is just best practice. If this doesn't fit the assignment, then you'll have to go with the malloc-related code duplication, which is a pitty).
As you defined the type NodePtr, it is confusing to see a mix of Node* and NodePtr in your code.
Your question was first not clear on whether the reversal of the list should be in-place or should build a new list without tampering with the initial list. From comments it became clear you needed a new list.
I probably didn't cover all problems with the code. Here is a corrected version:
#include <stdio.h>
#include <stdlib.h>
struct charNode {
char data;
struct charNode *nextPtr;
};
typedef struct charNode Node;
typedef Node *NodePtr;
NodePtr reverse(Node *stPtr);
void printList(Node *headPtr);
NodePtr createNode(int data, NodePtr nextPtr);
int main(void) {
NodePtr headPtr = NULL; // You need a pointer to the very first node
NodePtr tailPtr = NULL; // Maybe a better name for currentPtr
printf("Enter 10 letters to make a list: ");
for (int counter = 0; counter < 10; counter++) {
char input;
scanf("%c", &input);
NodePtr newNode = createNode(input, NULL);
if (headPtr == NULL) {
headPtr = newNode;
} else {
tailPtr->nextPtr = newNode;
}
tailPtr = newNode;
}
NodePtr revHeadPtr = reverse(headPtr);
puts("The list is:\n");
printList(headPtr);
puts("The reversed list is:\n");
printList(revHeadPtr);
}
void printList(NodePtr headPtr) {
while (headPtr != NULL) {
printf("%c --> ", headPtr->data);
// You can just move the head pointer: it is a variable local to this function
headPtr = headPtr->nextPtr;
}
puts("NULL\n");
}
NodePtr createNode(int data, NodePtr nextPtr) {
NodePtr newNode = malloc(sizeof(Node));
if (newNode == NULL) { // If malloc fails, exit the program
puts("Cannot allocate memory\n");
exit(1);
}
newNode->data = data;
newNode->nextPtr = nextPtr;
return newNode;
}
NodePtr reverse(NodePtr headPtr) {
NodePtr revHeadPtr = NULL;
while (headPtr != NULL) {
revHeadPtr = createNode(headPtr->data, revHeadPtr);
// You can just move the head pointer: it is a variable local to this function
headPtr = headPtr->nextPtr;
}
return revHeadPtr;
}

How can I pass a single pointer to a structure, inside a function and modify that structure variable?

In the below piece of code, I am able to modify the a variable used in main from the function.
#include<stdio.h>
int main()
{
int *a,b=10;
a = &b;
printf("%d\n",*a);
ref(a);
printf("%d\n",*a);
return 1;
}
int ref(int *a)
{
int b = 98;
*a = b;
return 1;
}
whereas, in the below piece of code, I couldnot able to do the same.
I know that we can modify a value which is in the main, from a function by using double pointer. I also know that we can use single pointer to modify, by returning the required address to the main and getting it in the main with the same data type. I just wanted to know whether I can modify a value in the main by passing it as a parameter to the function, only as a single pointer to the (structure) variable.
Note: I have denoted the working code with the comment '//WC'. Will be very thankful if someone can explain me the same.
//int insert(int data, Node **head) //WC
int insert(int data, Node *head)
{
Node *temp, *run;
temp = (Node *) malloc(sizeof(Node));
temp->data = data;
temp->next = NULL;
//if(*head == NULL) //WC
if(head == NULL)
{
printf("1st node\n");
//*head = temp; //WC
*head = *temp;
}
else
{
printf("node after first\n");
//run = *head //WC
*run = *head;
while(run->next != NULL)
{
run = run->next;
}
run->next = temp;
}
return 1;
}
int main()
{
Node *head;
insert(10, head);
insert(20, head);
insert(30, head);
insert(40, head);
insert(50, head);
return 1;
}
How can I pass a single pointer to a structure, inside a function and modify that structure variable?
TL;DR : you can modify the value pointed by the pointer, but you cannot modify the passed pointer itself.
C uses pass-by-value for function parameter passing. You cannot change the value of the received parameter from the called function and expect it to reflect in the variable used as the argument from the caller function.
However, in case of pointers, you usually don't modify the pointer itself, rather, we modify the value it points to. So, the changed value pointed by that pointer will be reflected in the caller function.
When you check if head is empty (has NULL value), you need to check the content of head (*head), not head itself since that means its own address. so if (head == NULL), should be *head == Null. head represents memory address of the pointer head and *head represents what is saved in that address(what is pointed to). With that logic, *head = temp; is correct as it will save the address of the dynamically allocated memory address -temp in head however the later one (*head = *temp) will attempt to copy/save content of temp to head which doesn't make sense since head is has only a size of a pointer and temp could be allocated whatever size the node is. I hope I helped at least a little bit and here is a working version of your code :)
int insert(int data, Node **head) //WC, This is correct because the parameter **head takes address of the pointer to the first node if any.
//int insert(int data, Node *head)
{
Node *temp, *run;
temp = (Node *) malloc(sizeof(Node));
temp->data = data;
temp->next = NULL;
if(*head == NULL) //WC, checking if head has any address value inside (not its own address)
{
printf("1st node\n");
*head = temp; //WC, because temp has address of the allocated memory and you wanna hold that address as the head / first node.
}
else
{
printf("node after first\n");
run = *head //WC
//*run = *head; you can't use this, one reason is because head could point to any size of memory (e.g 10000kb) and run has a size of a pointer, just few bytes.
while(run->next != NULL)
{
run = run->next;
}
run->next = temp;
}
return 1;
}
(Edit: multiple pointer use might complicate reading so I'd rather use the following struct defination)
typedef struct node* PNode; //Pointer to node
typedef struct node {
int item;
Pnode next;
} Node;
void insert(int data, PNode *head) {
PNode temp, run = *head;
temp = (PNode)malloc(sizeof(Node));
temp->data = data;
temp->next = NULL;
if (run == NULL){
*head = temp;
}//first node
else{
while (1) {
if (run->next == NULL) {
run->next = temp;
break;
}
run = run->next;
}
}
}

When printing out a linked list, why is the original head pointer not changed

I have written some code to create a singly linked list of integers and print out the items. After printing out all the items in the list, I printed out "head->item" and got the value of the integer in the first node.
I am quite puzzled as to why I can do that, because in the print() function, I wrote "head = head->next", so that means that head is changed right?
main()
int n;
int value;
ListNode *head = NULL;
ListNode *temp = NULL;
printf("Enter a value: ");
scanf("%d", &n);
while (n != -1)
{
if (head == NULL)
{
head = malloc(sizeof(ListNode));//create the head first
temp = head;//get temp to have the same value as head, so we do not accidently edit head
}
else
{
temp->next = malloc(sizeof(ListNode));//allocate space for the next node
temp = temp->next;//let temp be the next node
}
temp->item = n;//allocate a value for the node
temp->next = NULL;//specify a NULL value for the next node so as to be able to allocate space
scanf("%d", &n);
}
print(head);
printf("%d\n", head->item);//why can I still get the integer in the first node
while (head != NULL)
{
temp = head;
head = head->next;
free(temp);
}
head = NULL;
return 0;
}
void print(ListNode *head)
{
if (head == NULL)
{
return;
}
while (head != NULL)
{
printf("%i\n", head->item);
head = head->next;
}
}
head could be seen as a "reference" to a list, but it's actually a number (the address of the first node).
So a call to a function with head as a parameter just copy this "number" (the address) to the stack, and creates a new variable (which is also named head) initiated with the same address.
Since the head inside the function is a different variable, changing it doesn't change the original head.
Consider this situation:
void func(int x)
{
x=1;
}
...
int x=0;
func(x);
printf("%d",x); //Prints '0'
...
Make sure you understand why in this simple example the value of x isn't changed. It's true that pointers seem to change the behavior of parameter passing, but it doesn't mean that suddenly everything is passed "by reference".
Remember this rule: in order to modify the value of a variable in a function, you need to send a pointer to the variable. So what happens when you want to change a pointer to a variable? Well, according to the rule, you'll have to pass a pointer to the pointer.
So if you'd like to modify head (which you probably don't), refactor it like this:
void print(ListNode **head)
{
if (*head == NULL)
{
return;
}
while (*head != NULL)
{
printf("%i\n", *head->item);
*head = *head->next;
}
}
And the actual call is now print(&head).

Resources