I am implementing a linked-list in C with structure
struct node
{
int data;
struct node *next;
};
I have written the append function to add a node at the end of a linked-list, as below, and display function to display all the nodes. But display is giving segmentation fault due to some inconsistency in the append function I think. What can be wrong here? My book does have a similar function for append, using malloc. I want to know what is wrong in my function.
void append(struct node **q, int d)
{
struct node *temp;
temp = *q;
printf("\nBegin: Address at temp = %u", temp);
while (temp!= NULL){
temp = temp->next;
printf("\nTravel: Address at temp = %u", temp);
}
struct node p1;
p1.data = d;
p1.next = NULL;
*q=&p1;
printf("\nEnd: Address at *q = %u\n", *q);
printf("\n*q->data = %d next = %u", (*q)->data,(*q)->next );
}
void display(struct node *q)
{
printf("\n");
while (q != NULL){
printf(" -> %d",q->data);
q = q->next;
}
}
int main(int argc, char *argv[])
{
struct node *p;
p = NULL; /* empty linked list */
printf("\nNo. of elements in the Linked List = %d", count(p));
append(&p,1);
display(p);
append(&p,2);
display(p);
printf("\nNo. of elements in the Linked List = %d", count(p));
}
Output:
No. of elements in the Linked List = 0
Begin: Address at temp = 0
End: Address at *q = 6684096
*q->data = 1 next = 0
-> 1Segmentation fault
However, when I replace
struct node p1;
p1.data = d;
p1.next = NULL;
*q=&p1;
with
temp = *q;
*q = malloc(sizeof(struct node))
temp->data = d;
temp->next = NULL;
the error is gone.
Can someone explain the reason?
Here you use an address of a local variable in a way which makes it accessable after you left the function:
*q=&p1;
Then you leave the function.
Whenever that is accessed later, it will access memory which is NOT the local variable anymore.
You need to allocate the memory for the variable. Use malloc() for that.
E.g.:
struct node *p1;
p1 = malloc(sizeof(*p1));
/* skipping recommended check of success/NULL */
p1->data = d;
p1->next = NULL;
*q=p1;
There are more problems, like you let the list start with the new node, which is followed by NULL, which loses/leaks all of your previous list. But the immediate problem is caused by referencing the memory location of a bygone local variable after it exists.
regarding the loop:
while (temp!= NULL){
This results in temp containing NULL so this has stepped all the way through the linked list and off the end of the list.
Suggest:
while (temp->next != NULL){
as this will stop stepping through the linked list when it is pointing to the last 'node' in the linked list.
Then need to use temp as the pointer to the last 'node' in the linked list (where you want to append a new node)
regarding:
struct node p1;
p1.data = d;
p1.next = NULL;
*q=&p1;
this creates the new 'node' on the stack. However, anything on the stack 'disappears' when the function returns.
q is a pointer to the first 'node' in the linked list, not the last 'node' in the linked list. Suggest using temp as (after correcting 1) points to the last 'node' in the linked list
each 'node' needs to be created in the 'heap' memory, via malloc() or calloc() so it still exists after the function exits.
regarding:
temp = *q;
*q = malloc(sizeof(struct node))
temp->data = d;
temp->next = NULL;
the error is gone.
NO, the error is NOT gone. Rather, this always inserts the new 'node' as the second 'node' in the linked list. (and breaks the link to the following nodes of the linked list.)
the posted code fails to return all the allocated memory to the heap (via calls to free() ) The result is a memory leak for each and every call to malloc().
Related
I'm still learning how to program in C and I've stumbled across a problem.
Using a char array, I need to create a linked list, but I don't know how to do it. I've searched online, but it seems very confusing. The char array is something like this char arr[3][2]={"1A","2B","3C"};
Have a look at this code below. It uses a Node struct and you can see how we iterate through the list, creating nodes, allocating memory, and adding them to the linked list. It is based of this GeeksForGeeks article, with a few modifications. I reccommend you compare the two to help understand what is going on.
#include <stdio.h>
#include <stdlib.h>
struct Node {
char value[2];
struct Node * next;
};
int main() {
char arr[3][2] = {"1A","2B","3C"};
struct Node * linked_list = NULL;
// Iterate over array
// We calculate the size of the array by using sizeof the whole array and dividing it by the sizeof the first element of the array
for (int i = 0; i < sizeof(arr) / sizeof(arr[0]); i++) {
// We create a new node
struct Node * new_node = (struct Node *)malloc(sizeof(struct Node));
// Assign the value, you can't assign arrays so we do each char individually or use strcpy
new_node->value[0] = arr[i][0];
new_node->value[1] = arr[i][1];
// Set next node to NULL
new_node->next = NULL;
if (linked_list == NULL) {
// If the linked_list is empty, this is the first node, add it to the front
linked_list = new_node;
continue;
}
// Find the last node (where next is NULL) and set the next value to the newly created node
struct Node * last = linked_list;
while (last->next != NULL) {
last = last->next;
}
last->next = new_node;
}
// Iterate through our linked list printing each value
struct Node * pointer = linked_list;
while (pointer != NULL) {
printf("%s\n", pointer->value);
pointer = pointer->next;
}
return 0;
}
There are a few things the above code is missing, like checking if each malloc is successful, and freeing the allocated memory afterwards. This is only meant to give you something to build off of!
I am trying to add an item to the linked list by traversing the list to create the next node. and the last node in the list to point to the newly created node. But I am getting a core dump segmentation fault on it.
void linked_list_add(list_node_t *head, void *item)
{
list_node_t *temp = head;
while(temp->next != NULL)
{
temp = temp->next;
}
list_node_t *new_node = (list_node_t *)malloc(sizeof(list_node_t));
new_node->data = item;
new_node->next = NULL;
new_node->prev = temp;
//if(temp != NULL)
// temp->next = new_node;
// new_node->prev = temp;
}
TEST_F(LinkedList, Add)
{
int i = 3;
linked_list_add(list, &i);
ASSERT_EQ(list->next->data, &i);
i = 4;
linked_list_add(list, &i);
ASSERT_EQ(list->prev->data, &i);
i = 5;
linked_list_add(list, &i);
ASSERT_EQ(list->next->data, &i);
}
This is an answer to summarize the comments.
There are likely at least 3 issues with the code as written:
When the code void linked_list_add(list_node_t *head, void *item) is passed arguments, you generally want to be able to handle a NULL pointer for head. It looks like the while loop immediately goes into searching for the end of the list even if the head is null.
The newly added node, new_node gets the prev pointer updated so that the backwards searchs will be and shouldn't segfault. However, the forward searching isn't preserved. By this I mean that the last non-NULL node in the linked list doesn't have the next pointer pointing to the new_node.
The test ASSERT_EQ(list->prev->data, &i); is likely accessing either a random memory location or a NULL pointer. Given that the OP didn't post the declaration of the list struct it is difficult to say what the default values are/will be. However, unless this list is circular, the value of list->prev is an uninitialized pointer. Depending on your setup (e.g. if there is setup code for the linked list that sets the pointers to null, you could be accessing a NULL pointer there too.
I hope this helps the OP solve their coding problem(s).
I'm pretty new to C programming.
I have an assignment in which we are supposed to create a doubly linked list of integers, and write some functions to manipulate them. We are being asked to prevent memory leaks, but I'm not really sure how to do that.
I have to malloc a bunch of times in order to create and store nodes when making the linked list, and I'm pretty sure it's not a good idea to malloc enough space for a node and then free the pointer to it in the same place.
Therefore, my best guess is that I should free all nodes in the main function, when I will have printed their contents to the screen and they are no longer needed. I tried to implement a kill function that takes as input a reference head to the first node in the list, and which iterates over the nodes, freeing them as they go.
I went as far as installing valgrind to try and see if there were any memory leaks, and it looks like there are still some. I have no idea where they are coming from or how to fix the issue.
Here is the whole code:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
typedef struct Node{
int data;
struct Node *next;
struct Node *previous;
}Node;
void print_dll(Node *head){
Node *curr = head;
while(curr != NULL){
printf("%d\t", curr->data);
curr = curr->next;
}
puts(" ");
}
Node* create_dll_from_array(int array [], int arrSize){
//this is a function that creates a doubly linked list
//with the contents of the array
Node* current = (Node *) malloc (sizeof(Node * ));
current->data = array[arrSize-1];
current -> next = NULL;
for(int i = 2; i <= arrSize; i++){
//create a new node
Node * temp = (Node*)malloc(sizeof(Node*));
//I would like the dll to be in the same order as the array, I guess it isn't strictly necessary
temp ->data = array[arrSize-i];
temp -> next = current;
current-> previous = temp;
//now make temp the current
current = temp;
}
current-> previous = NULL;
return current;
}
void insert_after(Node* head, int valueToInsertAfter, int valueToInsert ){
if(head != NULL){
Node * current = head;
while(current-> data != valueToInsertAfter){
//this while loop brings 'current' to the end of the list if
//the searched value is not there
if(current-> next != NULL){
current = current->next;
}else{
break;
}
}
//after exiting this loop, the current pointer is pointing
//either to the last element of the dll or to the element
//we need to insert after
Node *new = (Node *) malloc (sizeof(Node *));
new->data = valueToInsert;
new->next = current->next;
new->previous = current;
if(current->next != NULL){
(current->next)->previous = new;
}
current->next = new;
}
}
void delete_element(Node* head, int valueToBeDeleted){
//work in progress
}
void kill(Node *head){
//this is my attempt at freeing all the nodes in the doubly linked list
Node *current;
while(head!=NULL){
current = head;
head = head->next;
free(head);
}
}
int main(){
int array [5] = {11, 2, 7, 22, 4};
Node *head;
/*Question 1*/
//creates a doubly linked list from the array below
head = create_dll_from_array(array, 5); ///size of the array is 5
/* Question 2 */
// print_dll(head);
/*Question 3*/
// to insert 13 after the first appearance of 7
insert_after(head, 7, 13);
print_dll(head);
//to insert 29 after first appearance of 21
insert_after(head, 21, 29);
print_dll(head);
/*Question 6*/
//create a function to free the whole list
kill(head);
return 0;
}
The main function here is given to us by the prof, we have to build out function around it.
I don't know why this is still appearing to lead to memory leaks, and if I', being honest, I don't really know where else they could occur. As far as I know, I need to keep all the memory until almost the last minute.
Please help, I'm pretty lost here.
Thank you!
There are two problems:
Need to change all malloc (sizeof(Node*)) to malloc (sizeof(Node))
Need to change free(header) to free(current) in the kill function.
The modified code is as follows
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
typedef struct Node {
int data;
struct Node *next;
struct Node *previous;
} Node;
void print_dll(Node *head)
{
Node *curr = head;
while(curr != NULL) {
printf("%d\t", curr->data);
curr = curr->next;
}
puts(" ");
}
Node *create_dll_from_array(int array [], int arrSize)
{
//this is a function that creates a doubly linked list
//with the contents of the array
Node *current = (Node *) malloc (sizeof(Node));
current->data = array[arrSize - 1];
current -> next = NULL;
for(int i = 2; i <= arrSize; i++) {
//create a new node
Node *temp = (Node *)malloc(sizeof(Node));
//I would like the dll to be in the same order as the array, I guess it isn't strictly necessary
temp ->data = array[arrSize - i];
temp -> next = current;
current-> previous = temp;
//now make temp the current
current = temp;
}
current-> previous = NULL;
return current;
}
void insert_after(Node *head, int valueToInsertAfter, int valueToInsert )
{
if(head != NULL) {
Node *current = head;
while(current-> data != valueToInsertAfter) {
//this while loop brings 'current' to the end of the list if
//the searched value is not there
if(current-> next != NULL) {
current = current->next;
} else {
break;
}
}
//after exiting this loop, the current pointer is pointing
//either to the last element of the dll or to the element
//we need to insert after
Node *new = (Node *) malloc (sizeof(Node));
new->data = valueToInsert;
new->next = current->next;
new->previous = current;
if(current->next != NULL) {
(current->next)->previous = new;
}
current->next = new;
}
}
void delete_element(Node *head, int valueToBeDeleted)
{
//work in progress
}
void kill(Node *head)
{
//this is my attempt at freeing all the nodes in the doubly linked list
Node *current;
while(head != NULL) {
current = head;
head = head->next;
free(current);
}
}
int main()
{
int array [5] = {11, 2, 7, 22, 4};
Node *head;
/*Question 1*/
//creates a doubly linked list from the array below
head = create_dll_from_array(array, 5); ///size of the array is 5
/* Question 2 */
// print_dll(head);
/*Question 3*/
// to insert 13 after the first appearance of 7
insert_after(head, 7, 13);
print_dll(head);
//to insert 29 after first appearance of 21
insert_after(head, 21, 29);
print_dll(head);
/*Question 6*/
//create a function to free the whole list
kill(head);
return 0;
}
Change sizeof(Node * ) to sizeof(Node) due to malloc reserving you memory for which the pointer points to and it needs the correct amount of needed memory (which is not a pointer but the object itself).
i <= arrSize might be an overflow, since the size usually is given as amount of memory cells. So you might consider using i < arrSize
The first while loop in the insert_after might point to invalid memory after the array
Node *new = is ugly syntax, since new is a keyword in C++. Please never do that, since that will break any code, which is being used in C++.
You dont need a temporary element in kill(). You can instead going until head points to NULL.
delete_element needs the same array checks as insert_after
Probably you need to debug the whole thing pasting one function after the other to get it properly working. No guarantee for correctness, since that was abit hard to read without comments and all.
The best way to find memory leaks is using valgrind (or a similar tool) in run time.
Valgrind will identify any memory leak or violation you ran through.
to run valgrind in linux environment, all you need to do is:
# valgrind --leak-check=full ./my_program
In you case it gave mainy theses errors:
==28583== Invalid read of size 8
==28583== at 0x400871: kill (aaa.c:77)
==28583== by 0x40092D: main (aaa.c:103)
==28583== Address 0x5204188 is 0 bytes after a block of size 8 alloc'd
==28583== at 0x4C2DB8F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==28583== by 0x40073A: create_dll_from_array (aaa.c:29)
==28583== by 0x4008D9: main (aaa.c:87)
this error means the allocation size was too small. as mentioned in another answers it is because you allocate enough memory for a pointer and not for the struct.
I have a struct called employee in my program with the following definition:
struct employee {
int id;
int age;
struct *employee next;
};
How would I take in input from the user, create a struct from their input, and create a singly linked list using pointers? I'm having a lot of issues figuring out how to do this dynamically. In Java, this is easily done through the constructor but how would you do this in C?
EDIT: Assuming the input is simply two ints (id and age).
This is how you create a new employee struct. You are dynamically allocating the memory using malloc function.
struct employee *new_employee = (struct employee*)malloc(sizeof(struct employee));
Now, we need to fill the data into this newly created employee field:
new_employee -> id = input_id;
new_employee -> age = input_age;
As for the next pointer, it is usually given NULL value. This is to prevent the next pointer from pointing to any arbitrary memory location.
new_employee -> next = NULL;
Finally, we have to link the list. To do that, you have to point the next pointer of the previous employee field to the current employee field (ex:as you mentioned in comment, first one (9,3) having a next pointer to the second one (3, 2))
Since it is a singly linked list, we cannot backtrack. So, there are two methods to access the previous field.
First is to maintain a pointer that points to the last field of the link list.
Second is to traverse the entire list till the end, and when you reach the last element, change its next pointer.
Implementation of the second method:
node *temp = *start;
if(temp!=NULL)
{
while(temp -> next)
temp = temp -> next;
temp -> next = new_employee;
}
Hope it helps!
Note : don't give me fish teach me how to fish
This is an example :
struct node {
int value;
struct *node next;
};
How to create new Node pointer dynamically ?
node* aux = (node*) malloc(sizeof(node));
How to get user input ( safely ) ?
char line[256];
int i;
if (fgets(line, sizeof(line), stdin)) {
if (1 == sscanf(line, "%d", &i)) {
/* i can be safely used */
}
}
How to create a linked list's head ?
/* This will be the unchanging first node */
struct node *root;
/* Now root points to a node struct */
root = (struct node *) malloc( sizeof(struct node) );
/* The node root points to has its next pointer equal to a null pointer
set */
root->next = 0;
/* By using the -> operator, you can modify what the node,
a pointer, (root in this case) points to. */
root->value = 5;
How to add new node to the linked list ?
/* This won't change, or we would lose the list in memory */
struct node *root;
/* This will point to each node as it traverses the list */
struct node *conductor;
root = malloc( sizeof(struct node) );
root->next = 0;
root->value = 12;
conductor = root;
if ( conductor != 0 ) {
while ( conductor->next != 0)
{
conductor = conductor->next;
}
}
/* Creates a node at the end of the list */
conductor->next = malloc( sizeof(struct node) );
conductor = conductor->next;
if ( conductor == 0 )
{
printf( "Out of memory" );
return 0;
}
/* initialize the new memory */
conductor->next = 0;
conductor->value = 42;
Now you must be able to solve the problem easily .
Happy Coding :D
For a month or two since i started learning data-structures , using C, i have been following a particular method of writing linked list. Which looks like this.
#include<stdio.h>
#include<stdlib.h>
struct Node{
int exponent;
int coeff;
struct Node *next;
};
typedef struct Node N;
N *st = NULL;
void insert(N *node, int c, int e){
N *temp;
node->exponent = e;
node->coeff = c;
if(st == NULL){
node->next = st;
st = node;
} else {
temp = st;
while(temp->next != NULL){
temp = temp->next;
}
node->next = temp->next;
temp->next = node;
}
printf(" %p", st); //this is written on purpose, not that i write it everytime
}
and i call this from the main method,
N *node = malloc(sizeof *node);
insert(node, 1, 2);
The output of the printf for four such calls is
00340D18 00340D18 00340D18 00340D18
i.e the value of the start pointer remains constant, but if i make a small change in the code
typedef struct Node N;
void insert(N *node, N *st, int c, int e){
N *temp;
node->exponent = e;
node->coeff = c;
if(st == NULL){
node->next = st;
st = node;
} else {
temp = st;
while(temp->next != NULL){
temp = temp->next;
}
node->next = temp->next;
temp->next = node;
}
printf(" %p", st);
}
and declare the the start pointer in the main method
N *strt = NULL;
node = malloc(sizeof *node);
insert(node, strt, 1, 1);
then run this four times like in the previous case, the values of start pointer gets changed
after each call
00560D18 00560D30 00560D48 00560D60
Why does this happen?
And if i want to pass the start pointer as a parameter what changes should be made?
Why does this happen?
This happens because the change to st is invisible to the caller. That is st = node has no effect whatsoever for the caller. The function changes its own copy and after the function returns, if the caller prints strt, it will still be NULL.
This is a somewhat subtle consequence of the fact that in C arguments are passed by value, even pointers. So you pass strt by value. You can change st->whatever because it's a pointer and changes will propagate to the caller but changing strt itself will not work.
And if i want to pass the start pointer as a parameter what changes
should be made
This is a regular question on this site and there is also a C FAQ that describes the problem. A simple if somewhat cumbersome change that you can do is have the function take a
N **st and pass &strt.
This is because strt in your main method and st in the modified function insert are two different variables. The function call
insert(node, strt, 1, 1);
copies the value of strt which is defined in main to the function parameter st which is a different variable and is allocated on the stack when the function insert is invoked. Any changes made to st is visible inside the function only because it's a local variable. It goes out of scope once the function returns. Therefore, strt defined in main is still pointing to null and never gets changed. This means that the condition st == NULL is always true and the if block in insert is always executed and the local variable st is set to the newly created node each time the function insert is called. This would, in fact, cause memory leak because you lose the handle on the node once the function insert returns.
What you should do is to pass an address of the variable strt to insert so that the changes made to it is visible in main. Since you always append the new node at the end of the linked list, I suggest a few more changes.
void insert(N *node, N **st, int c, int e) {
N *temp = *st;
node->exponent = e;
node->coeff = c;
node->next = NULL; // set it explicitly to NULL
if(*st == NULL) { // if head of the linked list is NULL
*st = node;
}
else {
while(temp->next != NULL) // reach the end of the linked list
temp = temp->next;
temp->next = node; // add the new node at the end
}
printf("%p", *st);
}
And in main, invoke the function as
// in main method
N *strt = NULL;
node = malloc(sizeof *node);
insert(node, &strt, 1, 1);