Double Pointers Queue, deQueue, enQueue - c

Currently preparing for exams and can't figure out the reasoning behind the queue[rear*] = new_node in this example code.
are you not putting the address of new_node in rather than the value?
Also, is the queue a Node ** queue because it is a pointer to a list of node pointers?
Thanks so much, I really appreciate it, no matter how many hours i spend on double pointers, they always crop up and retest my understanding i thought i finally had!
void enQueue(struct node **queue, int *rear, struct node *new_node)
{
queue[*rear] = new_node;
(*rear)++;
}
struct node *deQueue(struct node **queue, int *front)
{
(*front)++;
return queue[*front - 1];
}

Here queue is pointer to pointer to array of struct Node pointers.
Where each node pointer inside the array will point to NewNodes.
node 1 node2
^ ^
| .... |
+--------+---------+--------+
queue -->| node * | node * |node * |
+--------+---------+--------+
When you do
queue[*rear] = new_node;
You assign the node * at the *rear position inside the queue array to NewNode
Only reason I can think of for maintaining the Node * array is to avoid the copying the content of NewNode.

the variable rear is a pointer to an int. With *rear you get the value of that int. That value is then used as index.
It's equivalent to e.g.
int index = *rear;
queue[index] = new_node;
index++;
*rear = index;
It copies the value of the variable new_node (i.e. the address of where the pointer is pointing) into queue[index]. From this point onward, both new_node and queue[index] points to the same thing.
I hope that makes it clearer what's happening.

Related

How to dequeue a linked list in c if the element to be returned is not of primitive type?

I have this data structure:
typedef struct task
{
void (*function)(void *p);
void *data; // in my case, this is a struct with two integers
struct task *next;
}Task;
I want to have a dequeue function that returns the first element of type Task:
struct task* dequeue()
{
if (!head) {
return NULL;
}
Task *taskToReturn = head;
/********************
* PROBLEM'S HERE
********************/
head = head->next;
return taskToReturn;
}
Now, the problem is straightforward. I can't assign head to taskToReturn for the simple reason that I am changing the value pointed by head right after. How can I return an element that holds a struct and a function pointer and dequeue it?
Is it at all possible to get the element with a call like that?
Task *taskToDo = dequeue();
What you're doing to return the node you want is correct. The error here is that you're freeing the current head of the list. Stepping through the code:
Task *taskToReturn = head;
Here you're saving the current head in taskToReturn.
head = head->next;
Here you're repointing head to the second node in the list. Now head no longer points to the same node that taskToReturn points to.
free(head);
By doing this, you've lost you link to the rest of the list. Get rid of this line and you should be fine.

Understanding the logic behind building linked list using local reference

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.

Why we are defining head node and new node differently in linked list

struct node
{
int data;
struct node *next;
};
void addstart (struct node **n, int new_data){
struct node *new = (struct node*)malloc(sizeof(struct node));
new->data=new_data;
new->next=*n;
*n= new;
}
int main(){
struct node* head = NULL;
addstart(&head,5);
return 0;
}
i just want to know if head_node is also a new_node and both are same data type struct node then why we are defining it simply as
struct node* head = NULL;
and other nodes as:
struct node *new = (struct node*)malloc(sizeof(struct node));
struct node* head = NULL;
Because head is there to simply keeping track of the head of the list nothing else. Now don't the new node does the same?
yes it does. it keeps track of the memory that you allocate using malloc and then you point it out with subsequent node's next attribute.
head is of same type as newnode and both are same functonally. but we put a different meaning to head in that - we are making it point to the head of th list rather than making it a local variable which we can throw away.
Then also why head = NULL?
Ah! that's because we always create a node and make it's next attribute to point to the current head and then we change head to make the new node part of our linked list.
Initially the first node should be
+----+
| +------+
+----+ |
V
NULL (Well to make this NULL we just make head = NULL initially)
i want to know why we are not using malloc in head assignment case..
Because it's not needed - as simple as that. Why should we allocate an extra memory space and then assign it to head when the purpose of head is to just point to already allocated node. And when we add another extra node we add it to the head of the linked list and make it head. it's nothing other than pointing to the beginning of the list. That's it.
new is not a good variable name. Try some good one. Think a bit before naming a variable it will save you a lot of time in future.
Because when you declare head it doesn't have anything to point to yet, it indicates the list is empty , as soon as data is added it can point to the first node in the list.

why a pointer to List can also point to Node?

I am a primer to c programming and reading c primer: 5th edition. What confuse me is why plist as a pointer to List can also point to Node?
sorry, I did not paste function ListItemCount to the code block. In this function, Node * pnode = *plist;, Does that mean plist was converted as a ponter point to Node ? If so, why does the program need to convert to a pointer to node instead of assigning plist->head to pnode(a pointer to Node)?
typedef struct film {
char title[TSIZE];
int rating;
} Item;
typedef struct node{
Item item;
// typical usage
struct node * next;
} Node;
/*
* Note: to manage a linked list, we need a pointer to its beginning,
* and we've used typedef to make List the name for a pointer of this
* type.
*/
typedef struct list{
// should point to linked list Node
Node * head;
int size;
} List;
// TODO why `plist` as a pointer to List can also point to Node?
/* returns number of nodes */
unsigned int ListItemCount(const List * plist)
{
unsigned int count = 0;
Node * pnode = *plist; /* set to start of list */
while (pnode != NULL)
{
++count;
pnode = pnode->next; /* set to next node */
}
return count;
}
The compiler should shout warnings at you for that code.
However lets take a look at how it works...
The memory layout of the List structure is something like
+------+------+
| head | size |
+------+------+
(The above illustration ignores possible padding.)
The variable plist points to the beginning of that structure:
+------+------+
| head | size |
+------+------+
^
|
plist
As you can see it points to the location where head is stored. So by dereferencing plist we can get the head member.
But it is bad code and you should never write code like that. It makes code hard to read, understand and maintain. Be explicit and use
Node * pnode = plist->head; /* set to start of list */
instead.
So you know that this doesn't work.
How should it work?
Node * pnode = *plist;
This was intended to get the first node. It actually tries to assign the list type as the first node. To make it work, we need to get the head node out of that.
Node * pnode = (*plist).head;
This now actually returns a Node*
To write this more succinctly:
Node * pnode = plist->head;

Access structs through pointers

I'm working with linked lists. I'm having trouble accessing the data contained in a struct through a pointer. Here is my code:
void insertNode(Node **head, int num) {
Node *newNode = malloc(sizeof(Node));
newNode -> num = num;
while (head->next) { <-----problematic code
}
}
I've passed the address of the head pointer of the list into the function.
Node *list = malloc(arraySize * sizeof(Node));
Node *head = list;
insertNode(&head, randNum);
I keep getting an error that says "request for member "next" in something not a structure or union.
Node **head is a pointer to a pointer to a Node. So head-> is dereferencing a pointer to a pointer and therefore gives you a pointer. A pointer is not a struct or union, hence the error. You can use:
(*head)->
to dereference the underlying node.
Try (*head)->next in your loop.
Reason is simple, you send Node** but expect that it will work like a Node*, which is not correct.

Resources