pointer problem of circuit doubly LinkedList in C - c

Error was happend in main at bottom.
Add Node - data : 1 Segmentation fault (core dumped)
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
typedef struct Node
{
int data;
struct Node* prev;
struct Node* next;
}Node;
typedef struct List
{
Node* head;
Node* tail;
int count;
}List;
void InitList(List *list)
{
(list) = (List*)malloc(sizeof(List));
(list) -> head = NULL;
(list) -> tail = NULL;
(list) -> count = 0;
}
Node* CreateNode(int data)
{
Node* node = (Node*)malloc(sizeof(Node));
node -> data = data;
node -> prev = NULL;
node -> next = NULL;
return node;
}
void AddNode(List *list, Node* node)
{
if (!(list) || !node) return;
printf("Add Node - data : %d\n", node -> data);
if ((list) -> count == 0)
{
(list) -> head = (list) -> tail = node;
node -> next = node -> prev = node;
}
else
{
node -> prev = (list) -> tail;
node -> next = node -> prev = node;
(list) -> tail -> next = node;
(list) -> head -> prev = node;
(list) -> tail = node;
}
(list) -> count++;
}
int main()
{
List list;
InitList(&list);
for (int i = 1; i < 5; i++)
AddNode(&list, CreateNode(i));
return 0;
}
This is a code about circuit doubly LinkedList in C. There was exist original code and I revised that to know why at original multiple pointer was used. Error happened directly when AddNode(&list, CreateNode(i) was called in main.
(this was the site of the original code but not english)
(https://huiyu.tistory.com/entry/%EC%9E%90%EB%A3%8C%EA%B5%AC%EC%A1%B0-%EB%8F%99%EC%A0%81%ED%95%A0%EB%8B%B9%EC%9D%84-%EC%9D%B4%EC%9A%A9%ED%95%9C-%EC%97%B0%EA%B2%B0-%EB%A6%AC%EC%8A%A4%ED%8A%B8Linked-List-%EA%B5%AC%ED%98%84)
I expected that It'll be working because in main, I declared List list and then call InitList(&list). I thought it was call-by-reference but it didn't maybe.
I tried some tests, then I found tsomething.
I call the InitList with address of list typed List.
I expected that list would be initialized because I gave argument with address.
But when I printed the value of count of list, it was garbage value. (when I printed in InitList, that was 0)
So count was not zero while head and tail of list was NULL(found through assert), then Error happened.
I cannot understand why it was not call-by-reference, and why multiple pointers is needed.

Remember that arguments to functions are passed by value. That means the values in the call is copied into the functions local argument variables. All the function have is a copy, which is independent of the original variable or value from the call. That means
(list) = (List*)malloc(sizeof(List));
in your InitList will simply not work, you only modify the local list variable. The original value &list from the main function will not be modified. And in fact it cant.
This means that the List structure object you initialize in the InitList function, is not the same as the one in the main function. The List structure object in the main function will remain uninitialized.
It seems you have heard that emulating pass by reference works by passing pointers to variables. But you miss an important point: The pointer itself will still be passed by value.
The simple solution to your problem is to simply drop that assignment from the InitList function:
void InitList(List *list)
{
// list is already pointing to a properly allocated List structure
(list) -> head = NULL;
(list) -> tail = NULL;
(list) -> count = 0;
}
Other alternatives is to change list in the main function to a pointer, and pass a pointer to that pointer, which means that InitList must take a List **list argument. Or you define list as a normal local variable, do the allocation, and then return the pointer.

When you write List list; => memory is already allocated to list object now when you do malloc again inside the initlist() function then you point the pointer to a new memory location and hence this pointer which was earlier pointing to the location of list object is now pointing to some other address location. So all the changes that you made to this pointer in initlist functions are reflected to the struct object stored at some new address location (other than the list object).
Solution: Same as mentioned in other answers i.e. removing malloc line inside initlist function.

Or you can leave mallock() inside InitList function, but then You just need to define 'list' variable as a pointer to List structure in main() function:
List *list = NULL;

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 code for creating a singly linked list using double pointer in C

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.

Can't find the segmentation fault in my code

#include <stdio.h>
#include <stdlib.h>
typedef struct node{
struct node* next;
int value;
}Node;
int findLastNodeValue(Node* head){
while(head -> next != NULL){
head = head -> next;
}
return head -> value;
}
int main(){
Node *node1,node2;
node1 = (Node *)malloc(sizeof(Node);
node2 = NULL;
node1 -> next = node2;
findLastNodeValue(node1);
findLastNodeValue(node2);
return 0;
}
This code giving a segmentation fault. But I cannot find why does it occur. Can you help me with this one.
There are multiple issues with your code:
You are mallocing node1 yet you are not setting the value anywhere. This creates undefined behaviour whenever you try to access value - you might crash the program or you might get garbage data, which is usually worse since it then leads to other parts of your code acting weird.
You are not freeing the dynamically allocated memory. While in your case it's not such big of a deal it tells me that you are not familiar with the way dynamic allocation works (my belief is also strengthened by the first bullet point in this list). Whenever you malloc something, always free it (in C++ you have new and delete) and (to prevent unexpected behaviour) set the pointer to NULL.
node2 is not a pointer. The * in Node *node1, node2; applies only to the first variable. Each consecutive variable also needs a * otherwise it will be allocated on the stack.
By looking at your code it's clear that you want node2 to be a pointer (otherwise you wouldn't be assigning NULL as its value :)). In that case you are trying to access next of node2 but node2 is initialized to NULL:
int findLastNodeValue(Node* head){ // You are passing node2, which is NULL
while(head -> next != NULL){ // Can't access next of a NULL -> code breaks
head = head -> next;
}
return head -> value;
}
As a general rule do the following:
Try using a function that instantiates your node - since this is C you don't have a constructor I would suggest to write a function (or several depending on how much functionality you need) that generates a new node. This way you will ensure that at least there is no chance of not initializing a node
For example:
Node* createNode(int value) {
Node* node = (Node *)malloc(sizeof(Node));
if (!node) return NULL; // If malloc fails for some reason
node -> value = value;
node -> next = NULL;
return node;
}
Try using a function that deletes your node - if there is any chance of accessing a deleted reference again, set it to NULL and handle the NULL value accordingly
For example:
void deleteNode(Node** node) {
if (!*node) return;
free(*node);
*node = NULL;
}
Note that the code above doesn't delete what's reference by next since we only want to delete the node we are passing to the function. If you have previous (in the case of a double linked list), you will have to first access the next node, set its previous value to NULL and then delete your current node.
Whenever you pass a pointer, always check if that pointer is NULL before you do anything with the data that it's supposedly referencing. Combining this with the node creator function from the first point you can be certain that you are not passing some Node pointer that has not been initialized properly
Now as to your function in particular I would do the following:
int findLastNodeValue(Node* head) {
if (!head) return -1; // We have a null reference, so there is nothing else to do here; exit accordingly and check the return value to see if the function call has been successful
while(head -> next != NULL) {
head = head -> next;
}
return head -> value;
}
findLastNodeValue(node2) is your biggest problem. When you send NULL into findLastNodeValue, the very first thing you try to do is dereference the NULL pointer at the clause (head -> next != NULL).
To resolve this, you can check for and handle the case when head is NULL in your findLastNodeValue function before your while loop.

Adding an element to the end of an ordered list

I have just started learning about dynamic structures in C.
The first type that I'm trying to learn is the ordered list. I have created a few functions - namely, adding nodes to the beginning of the list and printing elements in the list, but then I decided to write a function that allows me to add elements to the end of the list. My function looks like this:
typedef struct Node* Node;
void add_end(Node *head, int value) {
Node new;
new = malloc(sizeof(struct Node));
new -> value = value;
new -> next = NULL;
if(*head == NULL) {
*head = new;
}
else {
Node help = *head;
while(help->next != NULL) {
help = help->next;
}
help->next = new;
}
}
Some clarification: My structure consists of two fields - value (int) and next (pointer to the next node).
Thus, my questions are:
1) Notice my substitution using the variable called "help" - when I tried to do this without it,namely writing *head wherever help appears now, and this function did not work properly - it only added as much as two elements. For example, if I pushed 1, 3, 5, 7 to the list, only 5 and 7 would be added. Why was this so? I really can't see any reasonable explanation.
2) At first I tried passing an argument of the type Node to the function (Not Node* as I'm doing now) and the function did not put anything to the list. Once again, I can't see the difference between writing using the type Node and writing the variable without the asterisk. Could you explain it to me in layman terms?
I know that my question may have a trivial answer, but please, be understanding - this is my first encounter with pointers and they may be quite complex to comprehend.
To try to answer your two questions:
Because you typedefed Node as typedef struct Node* Node; what you are passing into add_end as the first parameter is a double pointer to struct Node (like struct Node**). You then dereference it in your while loop with Node help = *head; This means that the value of the actual pointer is going to change. If you didn't have the help pointer, you would then keep moving head until you get to the end of the list. This means that you would only have two elements in the list -- the head itself and its next element.
The answer to this has to do with your typedef again. When you pass Node, with your typedef, you are only passing a single pointer to struct Node representing head, which means that dereferencing it will not give you the pointer to head, but the structure itself, which means that neither your if or else statements will work as intended, as your intent is to compare pointers.
Your function type should probably be:
void add_end(Node **head, int value) {
^
because head is a pointer to Node
Like:
void add_end(Node **head, int value) {
Node* new; // NOTICE Node*
new = malloc(sizeof(struct Node));
// TODO - add check for new being NULL
new -> value = value;
new -> next = NULL;
if(*head == NULL) {
*head = new;
}
else {
Node help = *head;
while(help->next != NULL) {
help = help->next;
}
help->next = new;
}
}
and call it like:
Node* head = NULL;
add_end(&head, 42);
add_end(&head, 42);
add_end(&head, 42);

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