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
Related
As most beginners in C, I'm implementing a simple linked list.
Each node for the list is defined as so:
typedef struct list_node {
void * data;
struct list_node * next;
} list_node_t;
I made a test program to create and iterate a list. Creation and insertion operations work correctly. However, the code below is giving me problems:
list_node_t * node = NULL;
list_iter_reset(list, node);
if (node == NULL) {
printf("Node is NULL.\n");
} else {
printf("Node is not NULL.\n");
}
fflush(stdout);
The function list_iter_reset() is defined below. Please note that list->head does not point to NULL, as I have inserted nodes in the list previously.
void list_iter_reset(list_t list, list_node_t * node)
{
node = list->head;
if (node == NULL) {
printf("Node is NULL.\n");
} else {
printf("Node is not NULL.\n");
}
fflush(stdout);
}
The output from executing that code is as follows:
Node is not NULL.
Node is NULL.
Since I'm passing a pointer to the node to the function, why is the created node in the test program still pointing to NULL after that function call?
I'm guessing a simple pointer arithmetic aspect went over my head here. I've been looking around and could not find a similar issue.
Thank you in advance.
The function is modifying the value of the pointer, but that never gets back to the caller. It seems you want to be passing a pointer to pointer (list_node_t**) to the function, not a regular pointer.
void list_iter_reset(list_t list, list_node_t** node)
{
*node = list->head;
...
}
The reasoning for this is that while a pointer is all you need to change the value of the thing it's pointing to, here you are trying to change the value of the pointer itself, i.e. where this pointer is pointing to.
As a comparison, imagine you would be passing an int to the function and expecting the function to modify that int. You would of course have to pass an int*, right? This is the same thing, except replace int with node*, and so you need to pass a pointer to that type, which in this case is node**
Assuming the relevant header files, functions for Singly Linked List in C are declared.
Is the following definition of Delete() correct?
/* The Structure for SLL
typedef struct SLL
{
int data;
struct SLL *next;
}node;
Function Delete() deletes a node*/
void Delete( node **head)
{
node *temp, *prev;
int key;
temp = *head;
if(temp == NULL)
{
printf("\nThe list is empty");
return;
}
clrscr();
printf("\nEnter the element you want to delete:");
scanf("%d", &key);
temp = search( *head , key);//search()returns the node which has key
if(temp != NULL)
{
prev = get_prev(*head, key);
if(prev != NULL)
{
prev->next = temp->next;
free(temp);
}
else
{
*head = temp->next;
free(temp);
}
printf("\nThe node is deleted");
getch();
}
}
1) What happens if I replace(node ** head) with (node *head)?
2) What happens if I replace void Delete (node **head) with node
*Delete(node *head)?
3) Is there an alternate way to delete a node in C?
Thanks in advance
This isn't a tutorial site, but here goes...
You do know that arguments in C are passed by value? Meaning the value is copied.
For example:
void some_function(int a)
{
// ...
}
When calling the function above, like
int x = 5;
some_function(x);
Then the value in x is copied into the argument a in the function. If the code inside the function assigns to a (e.g. a = 12;) then you only modify the local variable a, the copy. It does not modify the original variable.
Now, if we want the function to modify x, then we must emulate pass by reference, which is done using pointers and the address-of operator:
void some_function(int *a)
{
*a = 12; // Modify where a is pointing
}
Now to call that, we don't create a pointer variable and pass that (though it's possible as well), instead we use the address-of operator & to pass a pointer to the variable:
int x = 5;
some_function(&x); // Pass a pointer to the variable x
The pointer &x will be passed by value (since that's the only way to pass arguments in C), but we don't want to modify the pointer, we want to modify the data where it points.
Now back to your specific function: Your function wants to modify a variable which is a pointer, then how do we emulate pass by reference? By passing a pointer to the pointer.
So if you have
node *head;
// Initialize head, make it point somewhere, etc.
Now since the Delete function needs to modify where head points, we pass a pointer tohead`, a pointer to the pointer:
Delete(&head);
The Delete function of course must accept that type, a pointer to a pointer to node, i.e. node **. It then uses the dereference operator * to get where the pointer is pointing:
*head = temp->next;
1) If you replace node** head with node* head you won't modify the original head pointer. You probably have a head somewhere that marks the beginning of the linked list. When you delete a node, there's a chance that you want to delete head. In that case you need to modify head to point to the next node in the linked list.
*head = temp->next;
free(temp);
This part of your code does exactly that. Here, temp == head. We want head to point to head->next, but if we pass in node* head to the function, the pointer will get modified but the changes will disappear because you're passing the pointer by value. You need to pass in &head which will be of type node ** head if you want the changes to be reflected outside of the function.
2) You will then change the function definition to return a void pointer (which is a placeholder pointer that can be converted to any pointer. Take care to not break any aliasing rules with this. But the problem from (1) remains, although, you could return a modified head, and assign it to the returned value. In that case define the function won't fit well with other cases where the head doesn't need to be modified. So you could return a pointer for head if it's modified or return NULL when it doesnt. It's a slightly messier method of doing things imho, though.
3) Yes, but that depends on the way a linked list is implemented. For the datatype shown here, the basic delete operation is as given.
I am a C# programmer professionally, but trying to re-learn C. I have been writing a simple linked list in C. I have gotten it working fine when the head-node is defined in main(). But now I want to try and initialize the head-node in a function "initializeHead()".
Here is the Node definition and Main() function:
struct node
{
char value;
struct node * next;
};
int main()
{
struct node * head = NULL;
initializeHead(head, 'a');
return 0;
}
Function that initializes head node:
void initializeHead(struct node * head, char vertexCategory)
{
if (head == NULL)
{
head = malloc(sizeof(struct node));
head->value = vertexCategory;
head->next = NULL;
}
else
{
printf("\nError: Head already initialized!");
}
}
...After calling initializeHead(), it doesn't seem like anything has happened because head is still NULL.
How can this be accomplished?
The term method is not a normative term in C and C++. Use the term function instead (or member function in C++).
According to the C Standard the function main without parameters shall be declared like
int main( void )
In fact the head is already initialized in the declaration
struct node * head = NULL;
You can check for example whether a list is empty by using comparison
if ( head == NULL ) { /* ...*/ }
What you are trying to do using the function is to append a value to a list. So the function name initializeHead just confuses readers.
You can use instead either push, or push_front or some other suitable name.
The function shall be declared before its usage.
Arguments are passed to functions by values in C. The term passing by reference means in C to pass a pointer to the original object. Otherwise a function will deal with a copy of the original object.
You can imagine your function definition and its call the following way (for clarity I renamed the parameter name)
initializeHead(head, 'a');
//...
void initializeHead( /*struct node * list, char vertexCategory */ )
{
struct node *list = head;
char vertexCategory = 'a';
//...
That is function parameters are its local variables that are initialized by expressions used as arguments. So any changes of a parameter do not influence on the original argument. As it was mentioned above if you want to change an original object you have to pass it by reference that is indirectly through a pointer.
Also you should free all allocated memory by the list when the list is not used any more in the program to escape memory leaks.
The function should not issue a message . It is better if it returns a code of success or failure.
For example a function that pushes a value in a singly-linked list can look the following way
int push_front( struct node **head, char value )
{
struct node *new_node = malloc( sizeof( struct node ) );
int success = new_node != NULL;
if ( success )
{
new_node->value = value;
new_node->next = *head;
*head = new_node;
}
return success;
}
Pay attention to the first parameter declaration struct node **head. As the original head of the list has to be changed in the function then it is passed to the function by reference that is by using a pointer to it.
The function can be called like
push_front( &head, 'a' );
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.
2 Questions:
I'm writing a function to prepend a node to a list. Currently I have it like this:
void addList( NODE_TYPE** head, NODE_TYPE** d_name )
{
(*d_name)->next = *head;
*head = *d_name;
}
and inside main(), I call it like this:
addList( &head, &node_3);
My question is, is there another way to do this with a function prototype such as:
void addList( NODE *head, NODE *node);
?
This was a class problem, and I don't understand how prepending can be done with the above function prototype since calling the function would only pass in the value of the address, the caller would be unable to see any changes made to the head nor the node.
I'm unsure if my deleteList function is right. I want it so that the temp points to where head (anchor) points to. Then the next_free points to the 2nd node linked with the head. Then I free the first node. Then repeat for the second, third and so on, until all of them are freed.
void deleteList( NODE_TYPE** head )
{
NODE_TYPE* temp = *head;
NODE_TYPE* next_free = NULL;
while ( temp->next != NULL )
{
next_free = temp->next;
free( temp );
temp = next_free;
}
*head = NULL;
}
Is this the correct approach?
To answer number 1, you can use what's called a dummy head. That is an empty node whose next pointer points to the first element in your list. So you create your empty list as a single node, and then pass that node around knowing that its pointer won't change. This is useful if you intend to store pointers to the head of your list in multiple places but allow the list to change.
For number 2, it's almost right, but you want to make sure that *head is not NULL initially. Also, it won't delete a list containing only one element. Do this instead:
while ( temp != NULL )
And leave everything else the same.
Oh, another note about your first question. You are wrong when you say this:
calling the function would only pass in the value of the address, the
caller would be unable to see any changes made to the head nor the
node.
The contents of the node can change. You don't need a double pointer to it. The double pointer means the pointer can change.
You can avoid the extra "next_free" variable by directly assigning to *head:
void deleteList( NODE_TYPE **head )
{
NODE_TYPE *temp;
while ( (temp = *head) )
{
*head = temp->next;
free( temp );
}
}
"My question is, is there another way to do this with a function prototype such as:
void addList( NODE *head, NODE *node)"
Well you are right. If you just "pass by value" the changes you reflect will not apply to the original subroutine. What you can do is this:
Node_type * addList(Node_type *head, Node_type *d_name)
{
d_name->next=head;
return d_name;
}
In the caller function call in this format
head = addList( head, node_3);
This would reflect the change you want to see
For Q2
Just put the condition
while(temp!=NULL)
This would take care of the condition where there is an empty list or a list with single node