How to compare a pointer value with NULL in C - c

I was writing a function which removes a node in a linked list, whose input is a pointer to a linked list. If the function removes a linked list that has only one node, the function will make the pointer point to NULL. Here's part of the code:
void remove(dlinkNode_t *start){
//some previous code
if(start->next==NULL){//meaning we're removing the head of the linked list
dlinkNode_t current=start; //get a temp pointer to point at this node
start=NULL; //make start point to null
free(current); //free the head
return;
}
// More code
In main I created a linked list with one node, and passed this linked list to remove function to free it. Here's the code:
int main(){
dlinkNode_t *node1=create(); //creates a node and make node1 point at it
remove(node1); //now node1 should point at NULL
if(node1==NULL)
printf("hi");
return 0;
}
But I didn't see the hi printed. I don't know why the if statement didn't pass. Any ideas?

A new copy of the pointer is made in the local scope of remove. Any changes you make to the pointer will only be visible in that scope. Any changes that you make to the value being pointed to by a pointer will return to the calling scope.
You can solve this problem in one of two ways :
Return the edited pointer
node1 = remove(node1);
and make the change in remove as well.
dlinkNode_t * remove(dlinkNode_t *start){
//some previous code
//Function code
return start;
Or you can pass a pointer to the pointer start and then manipulate that pointer.
Function call :
remove(&node1);
Function definition :
void remove(dlinkNode_t **start){
//some previous code
if((*start)->next==NULL){ // meaning we're removing
// the head of the linked list
dlinkNode_t current=**start; //get a temp pointer
// to point at this node
**start=NULL; //make start point to null
free(current); //free the head

Related

Is a temporary variable needed when just passing the pointer to the first element of a linked list?

I have the following function to append a double value at the end of a linked list.
void deappendlinked(dNODE *head,double value){
while(head!=NULL){
if(head->next==NULL){
break;
}
head=head->next;
}
dNODE *newElement=memalloc(sizeof(dNODE));
newElement->data=value;
newElement->next=NULL;
head->next=newElement;
}
It receives the head, i.e., the address of the first element of the linked list, which I iterate through to the end.
As I'm not passing a pointer of a pointer, I do not need a temporary variable to hold the value of the head, correct? (I.e. I can just do what I did – at least it works.)
As I'm not passing a pointer of a pointer, I do not need a temporary variable to hold the value of the head, correct?
That is correct. The function will receive a copy of the pointer passed by the calling module. In that module, the value of that pointer will not be changed by your function (i.e. it will remain pointing at the head of the list).
As an aside, even if you know that your passed head value will not (read: should not) be NULL, it is still better to add a check for that, in case a future editor of your code does something silly.
Also, your while loop can be much simplified:
void deappendlinked(dNODE *head,double value) {
if (head == NULL) {
// Optional error message?
return;
}
while (head->next != NULL) head = head->next;
dNODE *newElement=memalloc(sizeof(dNODE));
newElement->data=value;
newElement->next=NULL;
head->next=newElement;
}

Not able to change state of a local variable in other function using pointer to that variable

I wrote a method to merge two sorted linked lists(LLs are in ascending order) into one. By using double pointer I passed address of my head pointer from calling function(main) to the called function(mergeSortedLL).
//definition of listNode
struct ListNode{
int data;
struct ListNode *next;
};
void mergeSortedLL(struct ListNode **headA,struct ListNode *prevA,struct ListNode **headB,struct ListNode *prevB)
{
struct ListNode *currA=*headA,*currB=*headB;
static struct ListNode *finalHead=NULL;
// Base Condition
if(!currA || !currB)
{
*headA=finalHead; // this should change head in main function
printList(*headA); // LINE-1 this function prints data of linked list sequentially.
return;
}
struct ListNode *nextA=currA->next, *nextB=currB->next;
if(currA->data>currB->data)
{
if(!finalHead)
finalHead=currB; // finalhead points to head of that LL which starts with smaller value node
currB->next=currA;
if(prevB)
prevB->next=currB;
mergeSortedLL(&currA,currB,&nextB,currB);
}
else
{
if(!finalHead)
finalHead=currA; //finalhead points to head of that LL which starts with smaller value node
currA->next=currB;
if(prevA)
prevA->next=currA;
mergeSortedLL(&nextA,currA,&currB,currA);
}
}
In the main function i have created two LL
head==> -1->3->5->6->8->9 first node is -1
head2==> 0->1->4->5->7->8->9
and after calling from main
mergeSortedLL(&head,NULL,&head2,NULL);
printList(head); //Line-2
Thing that i am not able to predict is Line-1 of mergeSortedLL function always prints desired sorted LL while printList method at Line-2 in main sometimes requires head to be passed and sometimes head2 to be passed for getting desired output (0113455678899).
for instance if first LL is changed to head==> 1->3->5->6->8->9, (first node is positive 1) Line-2 requires head2 to be passed instead of head to get the desired o/p.
How it is happening as in mergeSoretedLL method by means of double pointerd headA i am changing the head (of main function) to point to finalHead.
I think somehow values of headA and headB are getting swapped but i am not able to see it here.
Somebody please explain it.
You need to assign :
*headA=finalHead;
in the if and else statement as well.i.e, as below:
if(!finalHead) { // in if case
finalHead=currB;
*headA = finalHead;
}
...
...
if(!finalHead) { // in else case
finalHead=currA;
*headA = finalHead;
}
This is because when you call from main, currA and CurrB are not NULL because *headA and *headB are not NULL. So, your code enters if or else statement based on currA->data > currB->data is true or not. Here, you assign assign the finalHead to currA or currB, but, this is not reflected in *headA (head in main). So, obviously when you print from main, you won't get the result.
So, make sure that in the first recursion level, you assign the headA to the intended node's address.

delete a link list in c

I am solving a program to delete all the elements in a linked list and i encountered the following problem:
When i used a delete function with return type void, and checked if the start pointer is NULL in the main ,it wasn't and gives me absurd result
Code:
void deletes(struct node *start)
{
struct node *current,*next;
current=start;
while(current!=NULL)
{
next=current->link;
free(current);
start=next;
current=next;
}
start=NULL;
return ;
}
But if i change the return type, it works fine:
struct node *deletes(struct node *start)
{
struct node *current,*next;
current=start;
while(current!=NULL)
{
next=current->link;
free(current);
start=next;
current=next;
}
start=NULL;
return start;
}
Why is the start=NULL working in the first code?
My entire code is here
It's because in the first version you pass the list header by value, meaning the pointer to the head is copied, and you change only the copy in the function. Those changes are not visible after the function returns as no changes are made on the original copy.
Either do as you do in the second version, returning the result, or pass the pointer by reference, meaning you pass the address of the pointer (or a pointer to the pointer) using the address-of operator. Of course this means that you have to change the function as well:
void deletes(struct node **start)
{
struct node *current = *start;
/* Deleting the list... */
*start = NULL;
}
Call it like
struct node *list_head = ...;
deletes(&list_head);
Because in C, function arguments are passed by value. If you write start = NULL; inside a function, it will be ineffective outside of that function (it will only set the start pointer to NULL, which is essentially just a copy of the pointer value passed in, and it's local to the function.).
If you want to modify a function argument, you must pass a pointer to it. So,
void delete(struct node **start)
{
// ... delete ...
*start = NULL;
}
then
delete(&list);
would work.
It is because you should have (struct node **start), which can allow you to pass a pointer to the list so you can modify the list.
Currently you are only passing in a copy of the linked list to the function and therefore aren't changing the value of the actual list just a copy. Hence why when you return the copy you see the results

What happens internally when passing a pointer by value?

Suppose I have a following linked list structure:
struct linked_list
{
struct linked_list *next;
int data;
};
typedef struct linked_list node;
And the following function to print the linked list:
void print(node *ptr)
{
while(ptr!=NULL)
{
printf("%d ->",ptr->data);
ptr=ptr->next;
}
}
Now in the main() function when I write this:
print(head); // Assume head is the pointer pointing to the head of the list
This is essentially call-by-value. Because ptr in print will receive a copy of head. And we can't modify head from the print() function because its call-by-value.
But my doubt is, since ptr receives a copy of head but it's able to print the value of linked list. So does that means the print() function receives whole copy of linked list? If it does not receives the whole copy of linked list how its able to print the list?
Your function receives a copy of the pointer. The copy of the pointer points to the same place as the original pointer.
A pointer is like an address. Here's an analogy. Imagine writing your address down on a piece of paper. When you want to give it to a friend you copy the address: that is, you write the same address on a new piece of paper and give that paper to your friend. But if they go to the address written on their copy, they'll go to the exactly same place as if they had gone to the address on the original piece of paper.
print receives a copy of the address of head, which means that the data representing head isn't copied: the function is using the actual head and hence the actual linked list, not a copy.
The implications are that you can change head, e.g. head->data, and you can modify the rest of the linked list. The only thing that you can't do is change which node your passed-in pointer points to, i.e. you can't do head = NULL in print and expect that to be reflected outside print.
So, any of the following changes are all reflected outside the function:
// pick one:
ptr->data = 20;
ptr->next = NULL;
ptr->next = malloc(sizeof(node));
ptr->next->data = 20;
// etc.
The following aren't:
ptr = NULL;
ptr = malloc(sizeof(node));

Modifying head pointer in a linked list

I am having trouble understanding this code. All I really need is to modify the head pointer to point to the first element. So why won't *head work ? Changing the value of *head changes where this pointer points to and that should work, right ? I have read the pass by reference/pass by value, but am finding it hard to understand. Can someone help clarify this ?
Appreciate your help. Thanks.
In C/C++ it’s easier to make mistakes with pointer misuse. Consider this C/C++ code for inserting an element at the front of a list:
bool insertInFront( IntElement *head, int data ){
IntElement *newElem = new IntElement;
if( !newElem ) return false;
newElem->data = data;
head = newElem; // Incorrect!
return true;
}
The preceding code is incorrect because it only updates the local copy of the head pointer. The correct version passes in a pointer to the head pointer:
bool insertInFront( IntElement **head, int data ){
IntElement *newElem = new IntElement;
if( !newElem ) return false;
newElen->data = data;
*head = newElem; // Correctly updates head
return true;
}
You need help understanding the difference right?
Imagine the caller of the function in the first case:
IntElement *head;
int data;
...
insertInFront (head, data);
Now, in this case, the address pointed to by head is placed on the stack and passed in as an argument to insertInFront. When insertInFront does head = newElement; only the argument (on the stack) is modified.
In the second case, the caller would be:
IntElement *head;
int data;
...
insertInFront (&head, data);
In this case, the address of head is placed on the stack and passed in as an argument to insertInFront. When you do *head = newElement, this passed in address is de-referenced to get the address of the original list head, and that is modified.
Its fairly simple when you get your head around what a pointer is. In the first code IntElement *head, head is a pointer to the existing head of the linked list. So the caller is passing in the address of the head element of the list. Changing the value of head in the insert-in-front function doesn't change ANYTHING back at the caller. The value of that address was passed to your function - not what was holding that address back at the caller.
You need to pass your function 'the address of the address of the head' - or IntElement **head. This will allow this function to modify the address held by the caller - i.e. update the linked list to point to the new head.
You don't want to change the value head points to, you want to change the pointer that is stored in head itself, so don't use *head, use a pointer to head itself. Head is of type IntElement *, so the parameter should be a pointer to such a type: IntElement **
Whenever you have a value T x somewhere and you want some other function to modify it, you pass a pointer to x:
T x; // set to some value
modify_me(&x); // will change x
/* ... */
void modify_me(T * x)
{
*x = new_value;
}
Now just apply this mechanic to T = IntElement*. The values that you want to modify are themselves pointers!
(Maybe using a typedef would make things look less confusing: typedef IntElement * NodePtr;.)
Also note that your linked list is broken because you never set the "next" pointer of the new element to point to the old head, and similarly for the "previous" pointer if the list is doubly-linked.

Resources