void push(stack *head, int valuee)
{
if(head->next==NULL && head->value==-1)
{
head->value = valuee;
printf("First element %d inserted\n",valuee);
}
else
{
stack *temp = new stack;
temp->value = valuee;
temp->next = head;
head = temp;
printf("Element %d inserted\n",valuee);
}
}
First element is inserted properly but when i continue inserting elements, none of the elements are inserted after the first one.
Read somewhere that i have to pass pointer to pointer of stack but I did this same thing during a postfix infix question and it was working over there.
Help me with this problem here.
Many thanks for any help in advance
Previous example of infix postfix which was working fiine
void push(char c, stack *node)
{
stack *B = (stack *)malloc(sizeof(stack));
if (node->next == NULL)
{
node->next = B;
B->value = c;
B->next =NULL;
}
else
{
B->next = node->next;
node->next = B;
B->value = c;
}
}
You can change the function like this
stack* push(stack *head, int valuee)
//return void to stack *
return head;
//In the end return the new head
and it will work.
Call push like this
head = push(head,value);
Why u need pointer to pointer ?
You want to modify the contents of a pointer so if you pass only a pointer to the function it is pass by copy so you can not modify it actually.
In the case of infix-prefix scenario you must have not modified the string you would have read it only, so a pointer to pointer is not required.
For this line of code in the else portion of the if statement:
head = temp;
Your intention is to mutate head, in other words, change what head is pointing to. However, pointers are passed in as values, just like other variables. In other words, suppose I call the push function somewhere else. For simplicity, suppose I call it in the main function, something like this:
int main()
{
stack *headOfStack = new stack;
// suppose this next push triggers the else portion of the push code
push(headOfStack, 6);
}
Now, after the push(headOfStack, 6); statement has been executed, your intention is to expect headOfStack to point to a new "stack node" which contains the value 6. Now, headOfStack is a pointer to a variable of type stack. It stores a memory address. You can think of a memory address as some integer. When we call push, we are copying the content of headOfStack (the content of headOfStack is a memory address) into the local variable head of the push function. Therefore, when:
head = temp;
is executed, we are assigning the contents of temp to head. What is temp? It is a pointer to a variable of type stack. In other words, the value of temp is a memory address. So head = temp; simply assigns the memory address contained in temp to the local variable head. The local variable head in the push function and our headOfStack variable in the main function are two completely different variables with different memory addresses. If my explanation has been clear so far, this means that when we modify head in the push function, the headOfStack variable in main is totally unchanged.
What you want to do in this case is:
void push(stack **headPtr, int valuee)
{
// this will get the actual pointer we are interested in
stack *head = *headPtr;
if(head->next==NULL && head->value==-1)
{
head->value = valuee;
printf("First element %d inserted\n",valuee);
}
else
{
stack *temp = new stack;
temp->value = valuee;
temp->next = head;
// mutation is done here
*headPtr = temp;
printf("Element %d inserted\n",valuee);
}
}
And its usage, using our fictional main function:
int main()
{
stack *headOfStack = new stack;
// notice the use of &headOfStack instead of headOfStack
push(&headOfStack, 6);
}
Just remember that pointers store memory addresses, and that pointers are just variables, and they have memory addresses as well. To mutate a pointer (change what a pointer is pointing to), just pass in its memory address to the function.
Hope that helps!
EDIT for new edit in question
void push(char c, stack *node)
{
stack *B = (stack *)malloc(sizeof(stack));
if (node->next == NULL)
{
node->next = B;
B->value = c;
B->next =NULL;
}
else
{
B->next = node->next;
node->next = B;
B->value = c;
}
}
For this version of push, what it's doing is essentially:
If node->next == NULL, so node has no successor, then set its successor to a newly allocated node with value c
Otherwise, node->next != NULL and node has some successor. Then we would set the newly allocated node B to node's successor, and set node's original successor to be B's successor. Or in other words, it splices a new node B (with value c) in between node and its successor.
I am finding it quite hard to explain this, but a simple explanation is, this push does not change what node is pointing to. At nowhere did we show intention to mutate node. I think the stuff involving B should be quite understandable, so let's focus on the node->next assignments.
I am assuming that the stack is a struct that looks something like this:
struct stack {
char value;
struct stack *next;
};
Now, suppose in our main function, we have a stack:
stack x;
Notice that x is not a pointer. I think we all agree that doing x.value = something and x.next = something will mutate those fields.
Now, let's look at this:
stack *y = malloc(sizeof(struct stack));
We know that y stores an address to an actual struct stack (the actual struct stack is at *y). So y->value = something and y->next = something will mutate those fields.
So hopefully you can see why the node->value assignments work. Essentially node contains an address to an actual struct stack, whose value is *node. By pointer syntax, node->value and node->next assignments will change the contents of node.
Not a very good explanation I know. But just write more code. Pointers confused the hell out of me when I was first starting out with C. I think that these days, I can still be confused by 2 or 3 layers of indirection, and I've encountered some very nasty pointer bugs. Just practice more... some day you will really get it. I know it's what they all say, but it's true.
Related
I am trying to understand how the code below for creating a singly linked list works using a double pointer.
#include <stdio.h>
#include <stdlib.h>
struct Node {
int data;
struct Node* next;
};
void push(struct Node** headRef, int data) {
struct Node* newNode = (struct Node*)malloc(sizeof(struct Node));
newNode->data = data;
newNode->next = *headRef;
*headRef = newNode;
}
//Function to implement linked list from a given set of keys using local references
struct Node* constructList(int keys[], int n) {
struct Node *head = NULL;
struct Node **lastPtrRef = &head;
int i, j;
for(i = 0; i < n; i++) {
push(lastPtrRef, keys[i]);
lastPtrRef = &((*lastPtrRef)->next); //this line
if((*lastPtrRef) == NULL) {
printf("YES\n");
}
}
return head;
}
int main() {
int keys[] = {1, 2, 3, 4};
int n = sizeof(keys)/sizeof(keys[0]);
//points to the head node of the linked list
struct Node* head = NULL;
head = constructList(keys, n); //construct the linked list
struct Node *temp = head;
while(temp != NULL) { //print the linked list
printf(" %d -> ", temp->data);
temp = temp->next;
}
}
I understand the purpose of using the double pointer in the function push(), it allows you to change what the pointer headRef is pointing to inside the function. However in the function constructList(), I don't understand how the following line works:
lastPtrRef = &((*lastPtrRef)->next);
Initially lastPtrRef would be pointing to head which points to NULL. In the first call to push(), within the for loop in constructList(), the value that head points to is changed (it points to the new node containing the value 1). So after the first call to push(), lastPtrRef will be pointing to head which points to a node with the value of 1. However, afterwards the following line is executed:
lastPtrRef = &((*lastPtrRef)->next);
Whereby lastPtrRef is given the address of whatever is pointed to by the next member of the newly added node. In this case, head->next is NULL.
I am not really sure what the purpose of changing lastPtrRef after the call to push(). If you want to build a linked list, don't you want lastPtrRef to have the address of the pointer which points to the node containing 1, since you want to push the next node (which will containing 2) onto the head of the list (which is 1)?
In the second call to push() in the for loop in constructList, we're passing in lastPtrRef which points to head->next (NULL) and the value 2. In push() the new node is created, containing the value 2, and newNode->next points to head->next which is NULL. headRef in push gets changed so that it points to newNode (which contains 2).
Maybe I'm understanding the code wrong, but it seems that by changing what lastPtrRef points to, the node containing 1 is getting disregarded. I don't see how the linked list is created if we change the address lastPtrRef holds.
I would really appreciate any insights as to how this code works. Thank you.
This uses a technique called forward-chaining, and I believe you already understand that (using a pointer-to-pointer to forward-chain a linked list construction).
This implementation is made confusing by the simple fact that the push function seems like it would be designed to stuff items on the head of a list, but in this example, it's stuffing them on the tail. So how does it do it?
The part that is important to understand is this seemingly trivial little statement in push:
newNode->next = *headRef
That may not seem important, but I assure you it is. The function push, in this case, does grave injustice to what this function really does. In reality it is more of a generic insert. Some fact about that function
It accepts a pointer-to-pointer headRef as an argument, as well as some data to put in to the linked list being managed.
After allocating a new node and saving the data within, it sets the new node's next pointer to whatever value is currently stored in the dereferenced headRef pointer-to-pointer (so.. a pointer) That's what the line I mentioned above accomplishes.
It then stores the new node's address at the same place it just pulled the prior address from; i.e. *headRef
Interestingly, it has no return value (it is void) further making this somewhat confusing. Turns out it doesn't need one.
Upon returning to the caller, at first nothing may seem to have changed. lastPtrRef still points to some pointer (in fact the same pointer as before; it must, since it was passed by value to the function). But now that pointer points to the new node just allocated. Further, that new node's next pointer points to whatever was in *lastPtrRef before the function call (i.e. whatever value was in the pointer pointed to by lastPtrRef before the function call).
That's important. That is what that line of code enforces, That means if you invoke this with lastPtrRef addressing a pointer pointing to NULL (such as head on initial loop entry), that pointer will receive the new node, and the new node's next pointer will be NULL. If you then change the address in lastPtrRef to point to the next pointer of the last-inserted node (which points to NULL; we just covered that), and repeat the process, it will hang another node there, setting that node's next pointer to NULL, etc. With each iteration, lastPtrRef addresses the last-node's next pointer, which is always NULL.
That's how push is being used to construct a forward linked list. One final thought. What would you get for a linked list if you had this:
#include <stdio.h>
#include <stdlib.h>
struct Node
{
int data;
struct Node* next;
};
void push(struct Node** headRef, int data)
{
struct Node* newNode = (struct Node*)malloc(sizeof(struct Node));
newNode->data = data;
newNode->next = *headRef;
*headRef = newNode;
}
int main()
{
//points to the head node of the linked list
struct Node* head = NULL;
push(&head, 1);
push(&head->next, 2);
push(&head->next, 3);
for (struct Node const *p = head; p; p = p->next)
printf("%p ==> %d\n", p, p->data);
}
This seemingly innocent example amplifies why I said push is more of a generic insert than anything else. This just populates the initial head node.
push(&head, 1);
Then this appends to that node by using the address of the new node's next pointer as the first argument, similar to what your constructList is doing, but without the lastPtrRef variable (we don't need it here):
push(&head->next, 2);
But then this:
push(&head->next, 3);
Hmmm. Same pointer address as the prior call, so what will it do? Hint: remember what that newNode->next = *headRef line does (I droned on about it forever; I hope something stuck).
The output of the program above is this (obviously the actual address values will be different, dependent to your instance and implementation):
0x100705950 ==> 1
0x10073da90 ==> 3
0x100740b90 ==> 2
Hope that helps.
Below is the code for creation of linked list using local reference logic.
Not able to understand the code inside the for loop especially the 2nd line. (see // HERE)
Can somebody please elaborate how this logic is working.
void push(struct Node** head_ref, int new_data)
{
struct Node *newNode = (struct Node *)malloc(sizeof(struct Node));
newNode->data = new_data;
newNode->next = *head_ref;
*head_ref = newNode;
return;
}
struct Node* buildWithLocalRef()
{
int i=0;
struct Node *head = NULL;
struct Node **lastptrRef = &head;
for(i=1;i<6;i++)
{
push(lastptrRef,i);
lastptrRef = &((*lastptrRef)->next); // HERE
}
return head;
}
int main()
{
struct Node* head;
head = buildWithLocalRef();
printList(head);
return 0;
}
The technique you're seeing is building a linked list by forward-chaining. It is the most direct, and sensible way to build an ordered list from beginning to end, where the list does not have a tail pointer (and yours does not).
There are no "references" here. This isn't C++. This is using a pointer to pointer. The variable name is dreadfully named, btw. How it works is this:
Initially the list is empty, head is NULL
A pointer to pointer, lastptrRef will always hold the address of (not the address in; there is a difference) the next pointer to populate with a new dynamic node allocation. Initially that pointer-to-pointer holds the address of the head pointer, which is initially NULL (makes sense, that is where you would want the first node hung).
As you iterate the loop a new node is allocated in push . That node's next pointer is set to whatever value is in the pointer pointed to by lastptrRef (passed as head_ref in the function), then the pointer pointed to by lastptrRef is updated to the new node value.
Finally, lastptrRef is given the address of the next member in the node just added, and the process repeats.
In each case, lastptrRef hold the address of a pointer containing NULL on entry into push. This push function makes this harder to understand. (more on that later). Forward chaining is much easier to understand when done directly, and in this case, it would make it much, much easier to understand
struct Node* buildWithLocalRef()
{
struct Node *head = NULL;
struct Node **pp = &head;
for (int i = 1; i < 6; i++)
{
*pp = malloc(sizeof **pp);
(*pp)->data = i;
pp = &(*pp)->next;
}
*pp = NULL;
return head;
}
Here, pp always holds the address of the next pointer we'll populate with a new node allocation. Initially, it holds the address of head. As each node is inserted pp is set to the address of the next pointer within the latest node inserted, thereby giving you the ability to continue the chain on the next iteration. When the loop is done, pp holds the address of the next pointer in the last node in the list (or the address of head of nothing was inserted; consider what happens if we just pull the loop out entirely). We want that to be NULL to terminate the list, so the final *pp = NULL; is performed.
The code you posted does the same thing, but in a more convoluted manner because push was designed to push items into the front of a list (apparently). The function always sets the pointer pointed to by head_ref to the new node added, and the node's next is always set to the old value in *head_ref first. Therefor, one can build a stack by doing this:
struct Node* buildStack()
{
struct Node *head = NULL;
for (int i = 1; i < 6; i++)
push(&head, i);
return head;
}
Now if you print the resulting linked list, the number will be in reverse order of input. Indeed, push lives up to its name here. Dual-purposing it to build a forward-chained list is creative, I'll grant that, but in the end it makes it somewhat confusing.
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 learning how to make a linked list, but its failing to print out anything at all, and I cant figure out why??? please help. I believe it has something to do with my pointers but I don't know what it is.
#include <stdio.h>
#include <stdlib.h>
// typedef is used to give a data type a new name
typedef struct node * link ;// link is now type struct node pointer
/*
typedef allows us to say "link ptr"
instead of "struct node * ptr"
*/
struct node{
int item ;// this is the data
link next ;//same as struct node * next, next is a pointer
};
void printAll(link head); // print a linked list , starting at link head
void addFirst(link ptr, int val ); // add a node with given value to a list
link removeLast(link ptr); // removes and returns the last element in the link
//prints the link
void printAll(link head){
link ptr = head;
printf("\nPrinting Linked List:\n");
while(ptr != NULL){
printf(" %d ", (*ptr).item);
ptr = (*ptr).next;// same as ptr->next
}
printf("\n");
}
//adds to the head of the link
void addFirst(link ptr, int val ){
link tmp = malloc(sizeof(struct node));// allocates memory for the node
tmp->item = val;
tmp->next = ptr;
ptr = tmp;
}
// testing
int main(void) {
link head = NULL;// same as struct node * head, head is a pointer type
//populating list
for(int i = 0; i<3; i++){
addFirst(head, i);
}
printAll(head);
return 0;
}
output:
Printing Linked List:
Process returned 0 (0x0) execution time : 0.059 s
Press any key to continue
It's because you're passing a null pointer to your function and the condition for exiting the loop is for that pointer to be null, so nothing happens.
Your addFirst function takes a pointer's value, but it cannot modify the head that you declared inside of main().
To modify head you need to pass a pointer to link, then you can dereference that pointer to access your head and you can then change it.
void addFirst(link *ptr, int val ){
link tmp = malloc(sizeof(struct node));// allocates memory for the node
tmp->item = val;
tmp->next = *ptr;
*ptr = tmp;
}
Now you can change the head pointer. Just remember to pass the address to it when calling the function. addFirst(&head,i)
In the for loop
for(int i = 0; i<3; i++){
addFirst(head, i);
}
you create a bunch of pointers which all point to NULL. head is never changing since pointer itself is passed "by value". E.g. head is copied and all modifications to the pointer itself in addFirst are not visible outside.
This is the same as with say int. Imagine void foo(int x);. Whatever this function does to x is not visible outside.
However changes to the memory which link ptr points to are visible of course.
E.g. this line does nothing:
tmp->next = ptr;
ptr = tmp; <=== this line
}
You can fix this in several ways. One is to return new node from addFirst and another one is to make link ptr to be a pointer to pointer: link *ptr. Since in this case you want to change pointer value (not pointee value):
//link *ptr here a pointer to pointer
void addFirst(link * ptr, int val ){
link tmp = malloc(sizeof(struct node));// allocates memory for the node
tmp->item = val;
tmp->next = *ptr; //<<changed
*ptr = tmp; //<<changed
}
Do not forget to update declaration above also. And the call:
void addFirst(link * ptr, int val ); // add a node with given value to a list
...
for(int i = 0; i<3; i++){
addFirst(&head, i);
}
Then this code produces:
Printing Linked List:
2 1 0
Added:
It's important to understand that working with linked list requires working with two different types of data.
First is struct node and you pass around this type of data using links.
Second is head. This is a pointer to the very first node. When you would like to modify the head you find it is not a "node". It is something else. It's a "name" for the first node in the list. This name by itself is a pointer to node. See how memory layout for head is different from the list itself.
head[8 bytes]->node1[16 bytes]->node2[16 bytes]->...->nodek[16 bytes]->NULL;
by the way - the only thing which have lexical name here is head. All the nodes do not have name and accessible through node->next syntax.
You can also imagine another pointer here, link last which will point to nodek. Again this will have different memory layout from nodes itself. And if you would like to modify that in a function you will need to pass to function pointer to that (e.g.pointer to pointer).
Pointer and data it points to are different things. In your mind you need to separate them. Pointer is like int or float. It is passed "by value" to functions. Yes link ptr is already pointer and that permits you to update the data it points to. However the pointer itself is passed by value and updates to pointer (in your case ptr=tmp) are not visible outside.
(*ptr).next=xxx will be visible of course because data is updated (not pointer). That means you need to do one extra step - make changes to your pointer visible outside of function, e.g. convert the pointer itself (head) into data for another pointer, e.g. use struct node **ptr (first star here says this is pointer to a node, and the second star converts that pointer to data for another pointer.
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 5 years ago.
Improve this question
This is what I believe would be the better way.
int main()
{
node *head;
insertAfter(&head, 14, 12);
}
void insertAfter(node **head, int item, int after)
{
node *ptr, *loc;
loc = searchUnsorted(*head, after); //copy of *head passed
if(loc == (node *) NULL)
return;
ptr = (node*)malloc(sizeof(node));
ptr -> info = item;
ptr -> next = loc -> next;
loc -> next = ptr;
}
And this is what my teacher thinks would be it.
int main()
{
node *head;
insertAfter(head, 14, 12);
}
void insertAfter(node *head, int item, int after)
{
node *ptr, *loc;
loc = searchUnsorted(head, after); //copy of *head passed
if(loc == (node *) NULL)
return;
ptr = (node*)malloc(sizeof(node));
ptr -> info = item;
ptr -> next = loc -> next;
loc -> next = ptr;
}
I think the question should be "when should I pass a pointer (i.e. your teacher's version), and when should I pass a pointer to a pointer (i.e. your version)".
In the context of linked list, passing a pointer to a pointer makes sense if the function may exchange the head of the list. Consider, for example, a function called insertAtFront(node**head, int item), which will insert a value before the current head and therefore the caller has to be informed about the "new" head.
insertAtFront(node**head, int item) {
node *prevHead = *head;
*head = createNode(item); // assign *head a new value; caller's pointer value will change
*head->next = prevHead;
}
insertAtFrontWrong(node*head, int item) {
node *prevHead = head;
head = createNode(item); // only local variable head will get new value; caller's value will not change
head->next = prevHead;
}
int main() {
node *main_head = createNode(10);
insertAtFront(& main_head,20); // OK; afterwards main_head will point to the new head
insertAtFrontWrong(main_head,30); // Not OK; value of main_head will remain as is
}
However, if a function will by definition not exchange the head, it is not necessary to pass a pointer to a pointer; a "plain" pointer is sufficient:
void insertAfterSuperflousIndirection(node **head, int item, int after) {
// use (*head)->... to traverse/change successors
// *head will, however, never be set to a new value, so indirection is superfluous
}
void insertAfter(node *head, int item, int after) {
// use head->... to traverse/change successors
}
So in your case, if "insertAfter" will never exchange the head, I'd prefer the teacher's version.
You're teacher is trying to pass by value and you're trying to pass by reference. In my opinion your approach is better than teacher's. But it does vary from what you want to do with.
If you want your head pointer to be updated during the callee function then pass by reference is good. By this any changes done on head pointer memory location by the callee is updated also in the main.
Suppose head -> 0xabc123 ( Memory address of head) and content 0xadf432
Your teacher's theory
head of insertAfter() stores content of head(of main) ie 0xadf432 . You can play around with the nodes, But you cannot modify the content of head(of main) ie cant change the value of 0xabc123 to something else.
But in your approach you could do this. Thus able to change the head(of main) content ( problem after your function operations) your head may point to new node.........