why a pointer to List can also point to Node? - c

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;

Related

What is meant by struct node *next; in a linked list program made in c language?

// Linked list implementation in C
#include <stdio.h>
#include <stdlib.h>
// Creating a node
struct node {
int value;
struct node *next; //What is this, what are we doing here?
};
// print the linked list value
void printLinkedlist(struct node *p) {
while (p != NULL) {
printf("%d ", p->value);
p = p->next;
}
}
int main() {
// Initialize nodes
struct node *head;
struct node *one = NULL;
struct node *two = NULL;
struct node *three = NULL;
// Allocate memory
one = malloc(sizeof(struct node));
two = malloc(sizeof(struct node));
three = malloc(sizeof(struct node));
// Assign value values
one->value = 1;
two->value = 2;
three->value = 3;
// Connect nodes
one->next = two;
two->next = three;
three->next = NULL;
// printing node-value
head = one;
printLinkedlist(head);
}
I want to ask what are we doing here with this line of code?
it's in the creating a node part of the code (top).
struct node *next;
Are we assigning a pointer type struct variable for the sturct node but its inside of the same struct, assigning a variable named *next inside the same struct? But that isn't allowed, right?
we can either declare the variable out side the } and between ; or in the main()
function part of the code only, Isn't it?
Like
main()
{
struct node *next;
}
Again, then I came across a post mentioning it as a pointer to the structure itself, can anyone explaine how can we do this inside the same struct?
The next member points to another instance of struct node. Graphically, we usually represent it like this:
+–––––––+––––––+ +–––––––+––––––+
| value | next |––––> | value | next |
+–––––––+––––––+ +–––––––+––––––+
A struct type cannot contain an instance of itself - we can’t create a type like
struct node {
int value;
struct node next;
};
for two reasons:
The type definition isn’t complete until the closing }, and you cannot create an instance of an incomplete type;
The type would require infinite storage (struct node contains a member next of type struct node which contains a member next of type struct node which contains a member next of type struct node...);
However, we can declare next as a pointer to struct node, since we can create pointers to incomplete types. The size and representation of a pointer is independent of the size and representation of the type it points to.
What it means
The line struct node *next; is read as "next is a pointer to another struct node".
This is just a recursive structure declaration (definition):
struct node {
int value;
struct node *next; //What is this, what are we doing here?
};
It says a node consist of two parts:
an integer value
a pointer to another node.
The wiki article on linked lists has a nice visualization showing how one node points to another (or to NULL to end the chain).
How does it work?
As you noted, the interesting part is how the declaration can include a reference back to itself. The compiler handles this in two steps:
It sizes the struct as consisting of an int and a pointer (they're all the same size regardless of what they are pointing to).
Later it type checks the assignment and generates the appropriate assembly. When you write one->value = 1;, it makes sure the 1 is an integer and generates code to move 1 to the integer slot. And when your write one->next = two;, it verified that two is a pointer to a node and generates code to move that pointer to the second slot for the struct node pointer.

Double Pointers Queue, deQueue, enQueue

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.

Challenging the Node syntax

The following is a syntax, part of linked list in C programming language
struct tag-name
{
type member1;
type member2;
.......
.......
struct tag-name *next;
};
Why do we have to again write struct tag-name before the pointer variable next. Why can we not use void *next or int *next or something like that??
for a linked list the next entry (or whatever its named) must point to the next node. In your case the node type is tag-name.
so you need <type> next;
in C (different for c++) the way you ask for a pointer to a struct called x is to do struct x *. Hence the code you see that is confusing / upsetting you. Can you simplify it? Yes you can. C has typedef. You can do
typedef struct tag-name node;
and now you can have
struct tag-name
{
type member1;
type member2;
.......
.......
node *next;
};
You ask, can I have void* next. Yes but why do it? You will have to keep casting that pointer to a pointer to the struct (the compiler does not know implicitly what it points to), also a reader of the code will be surprised because they expect the next pointer to be a pointer to a node.
You ask can it be int next. No it cannot, the next object is a node, not an int
Think about the typical illustration of a linked list:
node node node
+------+------+ +------+------+ +------+------+
| data | next | --> | data | next | --> | data | next | --> ...
+------+------+ +------+------+ +------+------+
Each item in the list is a node of some type, and that node contains a next member that explicitly points to the next node in the list. In C, that typically translates to a struct type like
struct node
{
T data; // for some type T
struct node *next;
};
IOW, each struct node has a next member that points to another object of type struct node - not int, not void, etc., which is why we don't declare next as an int *, or a void *, or whatever.
However...
Depending on how you implement your list, you can use something other than a struct node * as your next item. Normally when we implement a list, we dynamically allocate each node using malloc as we need it. However, if you know that your list will never get bigger than some known, reasonably small value, you can set aside an array of struct node as your "heap", and your next member can be an array index value:
struct node
{
T data;
int next; // holds the *index* of the next element
} heap[SOME_SIZE];
You then initialize your "heap" so that each element explicitly points to the next in the array:
for ( int i = 0; i < SOME_SIZE-1; i++ )
{
heap[i].next = i+1;
}
heap[SOME_SIZE-1].next = -1; // use -1 to indicate "null"
Now, all you need is a couple of integers, one to point to the first available element in the array, and the other to point to the head of your list:
int avail = 0; // initially points to the first element in the "heap"
int head = -1; // initially "null"
"Allocating" a node then just becomes a matter of finding the first free node in the "heap":
int node = avail; // get the index of the next available node in the "heap";
avail = heap[avail].next; // update avail to point to the next available node
"Freeing" a node just means adding that index back to the head of the avail list:
heap[node].next = avail; // set this node point to the first free element
avail = node; // make this node the first free element;
Remember, node and avail are not node objects, they're simply indices into an array of node objects.
We typically don't do it this way because it's conceptually simpler for next to point to another struct node object directly, rather than be an index into an array. We can still use a fixed-sized array as our "heap", we just use the address of each element instead of its index.

Segfault when accessing next node in singly linked list

I'm trying to just reverse a singly linked list, but with a bit of a twist. Rather than having the pointer to the next node be the actual next node, it points to the pointer in that next node.
struct _Node
{
union
{
int n;
char c;
} val;
void *ptr; /* points to ptr variable in next node, not beginning */
int var;
};
typedef struct _Node Node;
I know how to reverse a normal singly linked list and I think I have the general idea of how to go about solving this one, but I'm getting a segfault when I'm trying to access head->ptrand I don't know why.
Node *reverse(Node *head)
{
Node * temp;
Node * prev = NULL;
while(head != NULL)
{
temp = head->ptr + 4; /* add 4 to pass union and get beginning of next node */
head->ptr = prev;
prev = head;
head = temp;
}
return prev;
}
Even if I try and access head->ptr without adding 4, I get a segfault.
The driver that I have for this code is only an object file, so I can't see how things are being called or anything of the sort. I'm either missing something blatantly obvious or there is an issue in the driver.
First, I'll show you a major problem in your code:
while (head) // is shorter than while(head != NULL)
{
// Where does the 4 come from?
// And even if: You have to substract it.
// so, definitively a bug:
// temp = head->ptr + 4; /* add 4 to pass union and get beginning of next node */
size_t offset_ptr = (char*)head->ptr - (char*)head;
// the line above should be moved out of the while loop.
temp = head->ptr - offset_ptr;
Anyways, your algorithm probably won't work as written. If you want to reverse stuff, you are gonna have to work backwards (which is non-trivial in single linked lists). There are two options:
count the elements, allocate an array, remember the pointers in that array and then reassign the next pointers.
create a temporary double linked list (actually you only need another single reversely linked list, because both lists together form a double linked list). Then walk again to copy the next pointer from your temporary list to the old list. Remember to free the temporary list prior to returning.
I tried your code and did some tweaking, well in my opinion your code had some logical error. Your pointers were overwritten again and again (jumping from one node to another and back: 1->2 , 2->1) which were leading to suspected memory leaks. Here, a working version of your code...
Node *reverse(Node *head)
{
Node *temp = 0;
//Re-ordering of your assignment statements
while (head) //No need for explicit head != NULL
{
//Here this line ensures that pointers are not overwritten
Node *next = (Node *)head->ptr; //Type casting from void * to Node *
head->ptr = temp;
temp = head;
head = next;
}
return temp;
}

Linked List access violation in C

Im not sure i got the concept of Linked List properly. What im trying to do is to create a linked list which receives the integer 6 as it's first "data". instead i get this access violation error when trying to write in the integer into the first node's data. is there something specific i missed here?
///////////////////////////////
typedef struct List_Node
{
int data;
struct List_Node* next;
}List_Node;
typedef struct List
{
List_Node* head;
}List;
////////////////////////////////
List* create_list();
void print_list(List_Node *x);
void add_to_node(List_Node *a,int val);
////////////////////////////////
void main()
{
List *a = create_list();
List_Node *ind = a->head;
printf("List:\n");
add_to_node(ind,6);
}
void print_list(List_Node *a)
{
while(a != NULL)
{
printf("%d \n",a->data);
a = a->next;
}
return;
}
void add_to_node(List_Node *a,int val)
{
a->data = val;
}
struct List* create_list()
{
struct List* list = (List*) malloc(sizeof(List));
list->head = NULL;
return list;
}
The code is dereferencing a NULL pointer as a->head is NULL:
list->head = NULL; /* inside create_list()` and 'list' returned to ...*/
List_Node *ind = a->head; /* ... inside main(), and then passed to */
add_to_node(ind,6); /* add_to_node() ... */
a->data = val; /* and dereferenced inside add_to_node(). */
Dereferencing a NULL pointer is undefined behaviour. To correct, malloc() memory for a List_Node and assign to a->head. Recommend creating an add_node() function that allocates memory and assigns the new int value to newly malloc()d node.
Do I cast the result of malloc?
As all have pointed out, you are dereferencing a NULL pointer as your list->head contains NULL.
Another thing I should point out is that, you are creating a List. but not any Node. There is no node in the list. You have to allocate memory for a Node and then use it.
So, instead of add_to_node(), you may use a function add_node that will take the list or the head and the value as parameters, create a node(i.e. allocating memory for the node), set the value and add it to the list.
Also, in your case, the structure List is redundant as it contains only one member. instead you can simply use List_node* head.
What you are doing:
In create_list:
Allocating memory for a List pointer.
Setting the list's head to NULL.
In add_to_node:
Setting the specified node pointer's data element to the specified val.
In main:
Creating a List pointer a by calling create_list. This list has a NULL head.
Initializing a List_Node pointer, ind, to point to the created list's head (which is NULL).
Trying to set ind's data element to 6 by calling add_to_node.
This is where your program is causing the access violation exception.
ind = NULL. Therefore NULL->data = undefined behaviour.
What you should be doing:
In create_list:
Allocate memory for a List pointer, say linked_list.
Allocate memory for linked_list's head pointer.
For the linked_list's head, initialize data and the next pointer to 0 and NULL respectively.
In add_to_node:
Do the same thing you're doing now.
In main:
Create a List pointer a by calling create_list. Now, this list will have a valid, initialized NULL head, but with no meaningful data.
Set the list's head data by calling add_to_node(a->head, 6);.
Note: This will only ensure you have a head node in your list. Nowhere are you creating additional nodes.

Resources