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.
Related
I am learning data structure, and here is a thing that I am unable to understand...
int end(struct node** p, int data){
/*
This is another layer of indirection.
Why is the second construct necessary?
Well, if I want to modify something allocated outside of my function scope,
I need a pointer to its memory location.
*/
struct node* new = (struct node*)malloc(sizeof(struct node));
struct node* last = *p;
new->data = data;
new->next = NULL;
while(last->next !=NULL){
last = last ->next ;
}
last->next = new;
}
why we are using struct node **p?
can we use struct node *p in place of struct node **p?
the comment which I wrote here is the answer I found here, but still, I am unclear about this here is the full code...
please help me
thank you
Short answer: There is no need for a double-pointer in the posted code.
The normal reason for passing a double-pointer is that you want to be able to change the value of a variable in the callers scope.
Example:
struct node* head = NULL;
end(&head, 42);
// Here the value of head is not NULL any more
// It's value was change by the function end
// Now it points to the first (and only) element of the list
and your function should include a line like:
if (*p == NULL) {*p = new; return 0;}
However, your code doesn't !! Maybe that's really a bug in your code?
Since your code doesn't update *p there is no reason for passing a double-pointer.
BTW: Your function says it will return int but the code has no return statement. That's a bug for sure.
The shown function (according to its name) should create a new node and apend it at the end of the list represented by the pointer to a pointer to a node of that list. (I doubt however, that it actually does, agreeing with comments...)
Since the list might be empty and that pointer to node hence not be pointing to an existing node, it is ncessary to be able to potentially change the pointer to the first elemet of that list away from NULL to then point to the newly created node.
That is only possible if the parameter is not only a copy of the pointer to the first node but instead is a pointer to the pointer to the first node. Because in the second case you can dereference the pointer to pointer and actually modify the pointer to node.
Otherwise the list (if NULL) would always still point to NULL after the function call.
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 have a structure like this
struct node
{
int data;
struct node* next;
};
Which I use to create singly linked list.
I created other functions like
int push(struct node* head,int element);
which pushes data onto stack created using node structs.
The function then tries to update the struct node* head passed to it using code(it does other things as well)
head=(struct node*)malloc(sizeof(struct node));
The call is made as such
struct node* stack;
push(stack,number);
It looks like this code created copy of the pointer passed to it. So I had to change the function to
int push(struct node** head,int element)
and
*head=(struct node*)malloc(sizeof(struct node));
The call is made as such
struct node* stack;
push(&stack,number);
So my question is, what was the earlier function doing? Is it necessary to pass struct node** to the function if I want to update original value of pointer or is my approach wrong?
Sorry I cannot provide complete code as it is an assignment.
C always passes by value. To change a variable passed to a function, instead of passing the variable itself, you pass a reference(its address).
Let's say you're calling your function with the old signature
int push(struct node* head,int element);
struct node *actual_head = NULL;
push(actual_head, 3);
Now before calling push, your variable actual_head will have value as NULL.
Inside the push function, a new variable head will be pushed to stack. It will have the same value as passed to it, i.e. NULL.
Then when you call head = malloc(...), your variable head will get a new value instead of actual_head which you wanted to.
To mitigate the above, you'll have to change the signature of your function to
int push(struct node** head,int element);
struct node *actual_head = NULL
push(&actual_head, 3);
Now if you notice carefully, the value of actual_head is NULL, but this pointer is also stored somewhere, that somewhere is its address &actual_head. Let's take this address as 1234.
Now inside the push function, your variable head which can hold the address of a pointer(Notice the two *), will have the value of 1234
Now when you do *head = malloc(...), you're actually changing the value of the object present at location 1234, which is your actual_head object.
C always passes parameters by value (i.e., by copying it). This applies even to pointers, but in that case, it is the pointer itself that is copied. Most of the times you use pointers, that is fine, because you are interested in manipulating the data that is pointed to by the pointer. However, in your situation, you want to modify the pointer itself, so you do indeed have to use a pointer to a pointer.
Yes.
The first version of your program was passing the pointer by value. Although it passed an address (held by the pointer to struct) it didn't pass the pointer's address - necessary to update the value.
Whenever you want to update a variable's value you must pass the variable's address. To pass a pointer address, you need a parameter pointer to pointer to type.
In your case, pointer to pointer to struct node.
The code is not doing what you think but not because it creates a copy of the node, it creates a copy of the pointer.
Try printing
fprintf(stdout, "Address of head: %p\n", (void *) head);
both, inside push() and in the caller function.
The pointer you pass in and the parameter have different addresses in memory although they both point to the same address, storing the result of malloc() in it doesn't persist after the funcion has returned.
You need to pass a pointer to the pointer like this
int push(struct node **head, int element)
{
/* Ideally, check if `head' is `NULL' and find the tail otherwise */
*head = malloc(sizeof(**head));
if (*node == NULL)
return SOME_ERROR_VALUE;
/* Do the rest here */
return SOME_SUCCESS_VALUE_LIKE_0;
}
And to call it, just
struct node *head;
head = NULL;
push(&head, value);
/* ^ take the address of head and pass a pointer with it */
of course, the push() implementation should be very differente but I think you will get the idea.
Everything everybody has said is absolutely correct in terms of your question. However, I think you should also consider the design. Part of your problem is that you are conflating the stack itself with the internal structures needed to store data on it. You should have a stack object and a node object. i.e.
struct Node
{
int data;
struct Node* next;
}
struct Stack
{
struct Node* head;
}
Your push function can then take a pointer to the Stack without any double indirection. Plus there is no danger of pushing something on to a node that is in the middle of the stack.
void push(struct Stack* stack, int value)
{
struct Node* node = malloc(sizeof node);
node->data = value;
node->next = stack->head;
stack->head = node;
}
The function
int push(struct node* head,int element) {
head=(struct node*)malloc(sizeof(struct node));
}
allocate some memory and throw it away (cause memory leak).
Passing “pointer to structure” to a function do create local copies of it.
It is necessary to pass struct node** to the function if you want to update original value of pointer. (using global variables is generally considered as a bad idea)
When you pass stack to your function push(struct node* head,int element)
and do
head=(struct node*)malloc(sizeof(struct node));
The pointer head will update to the memory allocated by malloc() and stack is unaware of this memory as you just passed the value.(which is uninitialized here)
When you pass the address then you have a pointer to pointer which makes the changes inside push() to be reflected on stack
So my question is, what was the earlier function doing?
Your earlier function was defined to receive a pointer to an object. You passed your function an uninitialized struct node pointer. A function can't do anything with a value representing an uninitialized pointer. So your function was passed garbage, but no harm was done because your function immediately ignored it by overwriting with a pointer to allocated memory. Your function is not using the value you passed for anything except temporary local storage now. Upon return from your function, your parameters to the function are thrown away (they are just copies), and the value of your stack variable is as it was before, still uninitialized. The compiler usually warns you about using a variable before it is initialized.
By the way, the pointer value to the allocated memory was also thrown away/lost upon function return. So there would now be a location in memory with no reference and therefore no way to free it up, i.e., you have a memory leak.
Is it necessary to pass struct node** to the function if I want to update original value of pointer or is my approach wrong?
Yes, it is necessary to pass the address of a variable that you want filled in by the function being called. It must be written to accept a pointer to the type of data it will supply. Since you are referencing your object with a pointer, and since your function is generating a pointer to your object, you must pass a pointer to a pointer to your object.
Alternatively, you can return a pointer as a value from a function, for example
struct node * Function() { return (struct node *)malloc(sizeof(struct node)); }
The call would be...
struct node *stack;
stack = Function();
if(stack == NULL) { /* handle failure */ }
So, your approach is not wrong, just your implementation (and understanding) need work.
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));
I have found this piece of code in a book:
void DeleteList(element *head)
{
element *next, *deleteMe;
deleteMe = head;
while (deleteMe) {
next = deleteMe->next;
free(deleteMe);
deleteMe = next;
}
}
Assuming that the argument that we are passing to the function is the pointer to the head of the list, why are we not passing a reference to that pointer?
If we don't do that, aren't we just going to delete a local copy of that pointer? That is why we pass reference pointers right? So the callee get the changes that have been done inside the function?
If we don't do that, aren't we just going to delete a local copy of that pointer?
Well, there is no such thing as a reference in C, but I assume you mean a pointer-to-pointer, and the answer would be no.
You are freeing the memory that the pointer points to on the heap, not the pointer itself. You are not mutating the pointer, so a copy is fine. Regardless of whether it is a copy or not, they point to the same place.
You are confusing this with assigning a completely new value to a variable passed to a function, in which case you would need to take a pointer-to-pointer. for example:
// only changes the local copy
void init(some_type *foo) {
foo = malloc(sizeof(some_type));
}
// initializes the value at *foo for the caller to see
void init(some_type **foo) {
*foo = malloc(sizeof(some_type));
}
Passing a pointer to a pointer (not a reference to a pointer, because C does not have references at all) would be a better solution, because you'd be able to null it out after the deletion. As it is currently defined, the function may leave dangling pointers behind if its caller is not careful. Other than that little problem, this solution is valid: the caller can always assign NULL to the list head manually after passing it to DeleteList().
Here is how I would rewrite this with a pointer to pointer:
void DeleteList(element **head) {
element *next, *deleteMe;
deleteMe = *head;
while (deleteMe) {
next = deleteMe->next;
free(deleteMe);
deleteMe = next;
}
*head = NULL;
}
The code from #dasblinkenlight can be made more compact.
void DeleteList(element **head) {
element *deleteMe;
while ((deleteMe = *head)) {
*head = deleteMe->next;
free(deleteMe);
}
}
When calling free, the pointer itself is not changed, so there is no need to pass it by reference.
You don't need to change the value of the head of the list in the caller.
// caller
DeleteList(head);
// head points to an invalid place (the place where the list used to be)
// for convenience sake, reset to NULL
head = NULL;