I have a problem with a problem that uses lists - c

I have a problem with this code. I have tried to debug with gdb and Valgrind, But nothing works...
The goal of the code is to create a list, where every string is added only if no existing node with the same string in already part of the list.
This is the code:
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
struct node {
char *word;
struct node *next;
};
void print_list(struct node *head) {
while ((head) != NULL) {
printf(" %s -> ", head->word);
head = (head->next);
}
}
// insert a new node in head
void add_n(struct node **head, char *str) {
struct node *new;
new = malloc(sizeof(struct node));
if (new == NULL) {
printf("Not enough memory\n");
exit(EXIT_FAILURE);
}
new->word = str;
new->next = NULL;
if ((*head) == NULL){
(*head) = new;
}
while ((*head)->next != NULL) {
head = &(*head)->next;
}
(*head)->next = new;
}
// check if str is present in the list
int find_string(struct node **head, char *str) {
int found = 0;
while ((*head) != NULL) {
int i = strcmp(str, (*head)->word); //i=0 are the same
if (i == 0) {
found = 1;
return found;
}
head = &((*head)->next);
}
return found;
}
// insert a new string in the list only if is new
void insert(struct node **head, char *str) {
if (find_string(head, str) == 0) {
add_n(head, str);
}
}
void rem_ent(struct node **head, struct node *ent) {
while ((*head) != ent) {
head = &((*head)->next);
}
(*head) = ent->next;
free(ent);
}
void fini_list(struct node **head) {
while ((*head) != NULL) {
rem_ent(head, *head);
head = &((*head)->next);
}
}
int main() {
struct node *head = NULL;
insert(&head, "electric");
print_list(head);
insert(&head, "calcolatori");
print_list(head);
insert(&head, "prova pratica");
print_list(head);
insert(&head, "calcolatori");
print_list(head);
fini_list(&head);
//printf("lunghezza media = %f\n", avg_word_lenght(head));
return 0;
}
Maybe the error might be stupid, but I spent a lot of time debugging without success.

the function fini_list invokes undefined behavior due to the redundant statement
head=&((*head)->next);
because the function rem_ent already set the new value of the pointer head.
void rem_ent(struct node** head, struct node * ent){
while((*head) != ent){
head= &((*head)->next);
}
(*head)= ent->next;
free(ent);
}
Remove the statement
void fini_list(struct node** head){
while((*head) != NULL){
rem_ent(head, *head);
}
}
Also change the function add_n the following way
// insert a new node in head
void add_n(struct node ** head, char* str){
struct node * new;
new = malloc(sizeof(struct node));
if (new == NULL) {
printf("Not enough memory\n");
exit(EXIT_FAILURE);
}
new->word= str;
new->next = NULL;
if ((*head)==NULL){
(*head)=new;
}
else
{
while((*head)->next != NULL){
head = &(*head)->next;}
(*head)->next = new;
}
}
And next time format the code such a way that it would be readable.
In general you should allocate dynamically memory for strings that will be stored in nodes of the list.

Related

How can I delete the front node of my doubly linked list?

I want to delete the front node in delete_first.
Here is the code:
#include <stdio.h>
#include <stdlib.h>
typedef int element;
typedef struct DListNode {
element data;
struct DListNode *llink;
struct DListNode *rlink;
} DlistNode;
void init(DListNode *phead) {
phead->llink = phead;
phead->rlink = phead;
}
An error occurs in the part below when I debug.
void print_dlist(DListNode *phead) {
DListNode *p;
for (p = phead->rlink; p != phead; p = p->rlink) {
printf("<-| |%d| |->", p->data);
}
printf("\n");
}
This is my insert code and I think it is not problem
void dinsert(DListNode *before, element data) {
DListNode *newnode = (DListNode *)malloc(sizeof(DListNode));
newnode->data = data;
newnode->llink = before;
newnode->rlink = before->rlink;
before->rlink->llink = newnode;
before->rlink = newnode;
}
I want to fix some error in that delete_first code but I don't know what is the problem and how to fix it.
void delete_first(DListNode *head) {
head = head->rlink;
if (head != NULL) {
head->llink = NULL;
}
free(head);
}
int main() {
DListNode *head = (DListNode *)malloc(sizeof(DListNode));
init(head);
printf("insert\n");
for (int i = 0; i < 5; i++) {
dinsert(head, i);
print_dlist(head);
}
printf("\n delete \n");
delete_first(head);
print_dlist(head);
free(head);
return 0;
}
How can I delete my front node using the head node?
To delete the first node of the doubly linked list, you must free the node pointed to by head->rlink unless head->rlink points to head itself, which is the case if the list is empty:
void delete_first(DListNode *head) {
DListNode *p = head->rlink;
if (p != head) {
p->llink->rlink = p->rlink;
p->rlink->llink = p->llink;
free(head);
}
}

Need clear understanding why value isn't affected even if passed by reference? [duplicate]

This question already has an answer here:
Dynamic memory access only works inside function
(1 answer)
Closed last year.
I have a question on which I seek clarity with pointers. I am coming from javascript so I am having a hard time with pointers. I have written singly linked list code mostly by myself and the code is fully working. I have created a function to delete the particular item in the linked list. The function in the main is this:
insertAtMiddle(&head, 3, 500);
insertAtMiddle(&head, 100, 500);
There is one thing I can't understand. First I would like to show the code of my delete function.
void insertAtMiddle(node_t **head, int location, int newData){
node_t *temp = *head;
while(temp->next != NULL){
if (temp->data == location)
{
break;
}
//Shouldn't that also change the original head or move the head to the left as it is passed by reference
temp=temp->next;
}
if (temp->data != location)
{
printf("No location found for replacement!");
}
//Create new node
node_t *newNode = malloc(sizeof(node_t));
newNode->data = newData;
newNode->next = temp->next;
temp->next = newNode;
}
My question is shouldn't the temp=temp->next; inside the while loop should also affect or modify the original head? Head has been passed as a reference to this function. My confusion arises because *temp = *head, temp has been assigned head.
My full code:
#include <stdio.h>
#include <stdlib.h>
typedef struct node {
int data;
struct node *next;
} node_t;
void viewAllNodes(node_t *head){
node_t *tmp = head;
printf("\n");
while (tmp != NULL)
{
printf("%d--->", tmp->data);
tmp=tmp->next;
}
printf("\n");
}
void insertAtBegining(node_t **head, int data){
node_t *tmp = malloc(sizeof(node_t));
tmp->data = data;
tmp->next = *head;
*head = tmp;
}
void deleteNode(node_t **head,int data){
node_t *tmp = *head, *nodeToDelete = NULL;
//see two nodes in advance
while(tmp->next != NULL){
if (tmp->next->data == data)
{
nodeToDelete = tmp->next;
break;
}
tmp = tmp->next;
}
if (nodeToDelete == NULL)
{
printf("No node found to delete");
return;
}
tmp->next = nodeToDelete->next;
free(nodeToDelete);
}
void insertAtEnd(node_t **head, int data){
node_t *newNode = malloc(sizeof(node_t));
newNode->data = data;
newNode->next = NULL;
node_t *tmp = *head;
while (tmp->next != NULL)
{
tmp = tmp->next;
}
tmp->next = newNode;
}
node_t *searchNode(node_t *head, int value){
node_t *tmp = head;
while (tmp->next != NULL)
{
if(tmp->data == value){
return tmp;
}
tmp=tmp->next;
}
return NULL;
}
void insertAtMiddle(node_t **head, int location, int newData){
node_t *temp = *head;
while(temp->next != NULL){
if (temp->data == location)
{
break;
}
//Shouldn't that also change the original head as it is passed by
temp=temp->next;
}
if (temp->data != location)
{
printf("No location found for replacement!");
}
//Create new node
node_t *newNode = malloc(sizeof(node_t));
newNode->data = newData;
newNode->next = temp->next;
temp->next = newNode;
}
int main(){
node_t *head = NULL;
insertAtBegining(&head, 1);
insertAtBegining(&head, 2);
insertAtBegining(&head, 3);
insertAtBegining(&head, 4);
insertAtBegining(&head, 5);
insertAtBegining(&head, 6);
insertAtEnd(&head, 8);
insertAtEnd(&head, 9);
insertAtBegining(&head, 100);
viewAllNodes(head);
deleteNode(&head, 1);
deleteNode(&head, 8);
insertAtMiddle(&head, 3, 500);
insertAtMiddle(&head, 100, 500);
viewAllNodes(head);
return 0;
}
You are basically doing this:
#include <stdio.h>
void foo(int* head) {
int temp = *head;
temp = 1234;
}
int main()
{
int bar = 0;
foo(&bar);
printf("bar = %d\n", bar);
}
You expect 1234 as output, but the actual output is 0.
temp is just a local copy, modifying temp will just modify temp and nothing else.

getting segmentation error (core dumped) in linked list

I have looked at my code several times but couldn't find the problem. please tell me what I need to replace to get my code working.
#include <stdio.h>
#include <stdlib.h>
#include <conio.h>
struct node
{
int data;
struct node *next;
};
struct node *head;
void insert(int x)
{
struct node *temp=(struct node *)malloc(sizeof(struct node));
temp->data = x;
temp->next = NULL;
if (head == NULL)
{
temp->next = head;
head = temp;
return;
}
struct node *temp1 = head;
while(temp1 != NULL)
{
temp1 = temp1->next;
}
temp1->next = temp;
}
void display()
{
struct node *temp = head;
if (head == NULL)
{
printf("list is empty");
return;
}
else{
while(temp!=NULL)
{
printf("%d ", temp->data);
temp = temp->next;
}
}
}
int main()
{
head = NULL;
insert(3);
insert(5);
insert(6);
display();
}
The problem is in this code:
struct node *temp1=head;
while(temp1!=NULL)
{
temp1=temp1->next;
}
temp1->next=temp;
... the while loop won't end until temp1 is NULL, so after the loop ends, it is guaranteed that temp1 is a NULL pointer ... and then you dereference that NULL pointer (via temp1->next), which causes a crash. Probably what you want to do instead is while(temp1->next != NULL) {...}
while(temp1!=NULL)
{
temp1=temp1->next;
}
temp1->next=temp;
The only way out of this loop is for temp1 to be NULL. Then the next line attempts to used temp1 as a pointer. This is likely causing your issue. You need to instead check if the next is NULL and break leaving temp1 as the last in the list not it's next.
Pro tip for linked lists like this, they are a lot easier to modify with double pointers. Example code:
void append(struct node **list, int a) {
// skip to the end of the list:
while (*list != NULL) {
list = &(*list)->next;
}
*list = malloc(sizeof(struct node));
(*list)->data = a;
(*list)->next = NULL;
}
void display(struct node *list) {
while (list) {
printf("%d\n", list->data);
list = list->next;
}
}
void remove(struct node **list, int index) {
while (*list) {
if (--index == 0) {
struct node *temp = *list;
*list = temp->next;
free(temp);
break;
}
}
}
int main() {
struct list *mylist;
append(&mylist, 3);
append(&mylist, 4);
append(&mylist, 5);
display(mylist); // prints 3 4 5
remove(&mylist, 1);
display(mylist); // prints 3 5
remove(&mylist, 0);
remove(&mylist, 0);
// mylist is NULL again, all memory free'd
}
Note that this code needs no special cases for "is the list empty?", which makes it less complex than yours.

Assigning NULL to the head node in a linked list in C

Please see the full code below.
I have an initial array named arr.
I'm using a linked list to store some indices via the append function. After I got the indices, I store them in linked list and use clearList to change the corresponding values to 0 (In this example arr[2] and arr[4]).
Finally, I free the memory by calling freeList since i'm done with the linked list.
However, to be able to do same thing again and again, I need to set head to NULL whenever I call freeList. But I cannot. Any idea how to solve this?
Thank you.
#include <stdio.h>
#include "gurobi_c.h"
#include <stdlib.h>
//Gurobi variables
GRBenv *env = NULL;
GRBmodel *model = NULL;
//Gurobi variables
struct Node
{
int data;
struct Node *next;
struct Node *end;
};
void append(struct Node** head_ref, int new_data)
{
struct Node *last = *head_ref;
struct Node* new_node = (struct Node*) malloc(sizeof(struct Node));
new_node->data = new_data;
new_node->next = NULL;
new_node->end = new_node;
if (*head_ref == NULL)
{
*head_ref = new_node;
//printf(" ..Init Append %d\n",new_data);
return;
}
last = (*head_ref)->end;
last->next = new_node;
(*head_ref)->end=new_node;
//printf(" ..Append %d\n",new_data);
return;
}
void clearList(struct Node *node, double *arr)
{
int i;
if(node!=NULL)
{
struct Node tmp;
tmp=*(node->end);
while (node != NULL)
{
i=node->data;
arr[i]=0;
//printf(" ..clear %d \n", node->data,(node->end)->data);
node = node->next;
}
}
}
void freeList(struct Node *node)
{
struct Node *tmp,*hd;
hd=node;
while (node != NULL)
{
tmp=node;
node = node->next;
//printf(" ..Free %d \n", tmp->data);
free(tmp);
}
hd=NULL;
}
int main (){
Node *head;
double *arr = (double *) malloc(sizeof(double) * 10);
for(int i=0;i<10;i++)
arr[i]=i;
head=NULL;
printf("Head: %s\n", head);
append(&head,2);
append(&head,4);
clearList(head,arr);
for(int i=0;i<10;i++)
printf("No %d : %.2f\n",i,arr[i]);
freeList(head);
free(arr);
printf("%s", head);
getchar();
return 0;
}
You're already changing the value of head in your append function so you basically need to do the same thing in freeList:
void freeList(struct Node **head_ref)
{
struct Node *tmp,*node;
node=*head_ref;
while (node != NULL)
{
tmp=node;
node = node->next;
//printf(" ..Free %d \n", tmp->data);
free(tmp);
}
*head_ref=NULL;
}
int main (){
/* do stuff */
freeList(&head);
/* do stuff */
}
Just for completeness: Another possible option would be to use a wrapper macro for freeList().
void freeList(struct Node *node)
{
/* ... */
}
#define freeListNull(node) do { \
freeList(node); \
node = NULL; \
} while(0)
int main () {
/* ... */
freeListNull(head);
/* ... */
}
This solution has a similar disadvantage as the version that returns the modified pointer. You can simply forget to use the right call freeListNull(head); and call freeList(head); instead. The best solution is a function freeList() that takes the address of the head pointer as in idk's answer.
I realized it is possible to change the freeList function so that it will return a NULL value. See the updated code below:
#include <stdio.h>
#include "gurobi_c.h"
#include <stdlib.h>
//Gurobi variables
GRBenv *env = NULL;
GRBmodel *model = NULL;
//Gurobi variables
struct Node
{
int data;
struct Node *next;
struct Node *end;
};
void append(struct Node** head_ref, int new_data)
{
struct Node *last = *head_ref;
struct Node* new_node = (struct Node*) malloc(sizeof(struct Node));
new_node->data = new_data;
new_node->next = NULL;
new_node->end = new_node;
if (*head_ref == NULL)
{
*head_ref = new_node;
//printf(" ..Init Append %d\n",new_data);
return;
}
last = (*head_ref)->end;
last->next = new_node;
(*head_ref)->end=new_node;
//printf(" ..Append %d\n",new_data);
return;
}
void clearList(struct Node *node, double *arr)
{
int i;
if(node!=NULL)
{
struct Node tmp;
tmp=*(node->end);
while (node != NULL)
{
i=node->data;
arr[i]=0;
//printf(" ..clear %d \n", node->data,(node->end)->data);
node = node->next;
}
}
}
Node* freeList(struct Node *node)
{
struct Node *tmp;
while (node != NULL)
{
tmp=node;
node = node->next;
printf(" ..Free %d \n", tmp->data);
free(tmp);
}
return NULL;
}
int main (){
Node *head;
double *arr = (double *) malloc(sizeof(double) * 10);
for(int i=0;i<10;i++)
arr[i]=i;
head=NULL;
printf("Head: %s -> null as expected\n", head);
append(&head,2);
append(&head,4);
clearList(head,arr);
for(int i=0;i<10;i++)
printf("No %d : %.2f\n",i,arr[i]);
printf("Head: %s -> Not null as linkedlist is not freed\n", head);
head=freeList(head);
printf("Head: %s -> Again null as expected\n", head);
free(arr);
printf("%s", head);
getchar();
return 0;
}

storing and printing string in void pointer

I have written a linked list program which stores data member as void *.
while trying to store annd print using scanf/printf functions, I am getting segmentation fault.
node definition -->
typedef struct node {
struct node *next;
void *data;
}node;
main function -->
head=(node *)malloc(sizeof(node));
if (head==NULL){
printf("error in allocation of memory\n");
exit(EXIT_FAILURE);
}
tail=(node*)create(head);
create function -->
void *create(node *current)
{
int user_choice;
while(current){
printf("\nEnter the data:");
scanf("%s",current->data);
printf("stored at %p\n",(void*)current->data);
printf("%s",(char*)current->data);
printf("\nType '1' to continue, '0' to exit:\n");
scanf("%d",&user_choice);
if(user_choice == 1){
current->next=(node*)malloc(sizeof(node));
current=current->next;
}
else{
current->next=NULL;
}
}
return current;
}
can anyone tell what is the correct argument for scanf & prinf should be..?
working code after incorporating points given in answers...
void *create(node *current)
{
node *temp;
int user_choice;
while(current){
printf("\nEnter the data:");
current->data=(char*)malloc(10*sizeof(char));
scanf("%s",current->data);
printf("stored at %p\n",(void*)current->data);
printf("%s",(char*)current->data);
printf("\nType '1' to continue, '0' to exit:\n");
scanf("%d",&user_choice);
if(user_choice == 1){
current->next=(node*)malloc(sizeof(node));
}
else{
current->next=NULL;
temp=current;
}
current=current->next;
}
return temp;
}
In your code,
scanf("%s",current->data);
is attempt to make use of an unitialized pointer, it invokes undefined behavior.
You need to follow either of bellow approach,
make the pointer point to valid chunk of memory (using malloc() and family for dynamic allocation, for example)
use an array.
You should first initialize data member of structure because
current->data = malloc("passes size here");
For putting data you have to typecast first this data because void is not storage type. void pointer can be used to point to any data type.
Like
*(char *)(current->data) = 1;
As others have said:
scanf("%s",current->data);
Is undefined in C. current->data needs to be pointing somewhere before you can store anything in it.
You should instead:
Accept input from scanf.
Store in temporary buffer.
Insert into linked list
print out whole linked list at the end
free() linked list at the end.
I also feel that your current void *create function is doing too much, and it would be easier to split up your code into different functions, just to make it easier to handle all the pointer operations, inserting etc.
To demonstrate these points, I wrote some code a while ago which does these things, and has been modified to help you with your code. It is not the best code, but it does use these points that will help you with your code.
Here it is:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAXSTRLEN 100
typedef struct node {
void *data;
struct node *next;
} node_t;
typedef struct {
node_t *head;
node_t *foot;
} list_t;
list_t *create_list(void);
node_t *generate_node(void);
list_t *insert_node(list_t *list, char *data);
void print_list(list_t *list);
void free_list(list_t *list);
int
main(int argc, char *argv[]) {
list_t *list;
char data[MAXSTRLEN];
int user_choice;
list = create_list();
while (1) {
printf("Enter the data: ");
scanf("%s", data);
printf("\nType '1' to continue, '0' to exit:\n");
if (scanf("%d",&user_choice) != 1) {
printf("Invalid input\n");
exit(EXIT_FAILURE);
}
if (user_choice == 1) {
list = insert_node(list, data);
} else {
list = insert_node(list, data);
break;
}
}
print_list(list);
free_list(list);
list = NULL;
return 0;
}
/* inserting at foot, you can insert at the head if you wish. */
list_t
*insert_node(list_t *list, char *data) {
node_t *newnode = generate_node();
newnode->data = malloc(strlen(data)+1);
strcpy(newnode->data, data);
newnode->next = NULL;
if (list->foot == NULL) {
list->head = newnode;
list->foot = newnode;
} else {
list->foot->next = newnode;
list->foot = newnode;
}
return list;
}
node_t
*generate_node(void) {
node_t *new = malloc(sizeof(*new));
new->data = NULL;
return new;
}
void
print_list(list_t *list) {
node_t *curr = list->head;
printf("\nlinked list data:\n");
while(curr != NULL) {
printf("%s\n", (char*)curr->data);
curr = curr->next;
}
}
list_t
*create_list(void) {
list_t *list = malloc(sizeof(*list));
if (list == NULL) {
fprintf(stderr, "%s\n", "Error allocating memory");
exit(EXIT_FAILURE);
}
list->head = NULL;
list->foot = NULL;
return list;
}
void
free_list(list_t *list) {
node_t *curr, *prev;
curr = list->head;
while (curr) {
prev = curr;
curr = curr->next;
free(prev);
}
free(list);
}
UPDATE:
Also note how I allocated memory for newnode->data?
Like this:
newnode->data = malloc(strlen(data)+1); //using buffer from scanf
This now means I can store data in this pointer, your current->data will need to do something similar.
working code-->
void *create(node *current)
{
node *temp;
int user_choice;
while(current){
printf("\nEnter the data:");
current->data=(char*)malloc(10*sizeof(char));
scanf("%s",current->data);
printf("stored at %p\n",(void*)current->data);
printf("%s",(char*)current->data);
printf("\nType '1' to continue, '0' to exit:\n");
scanf("%d",&user_choice);
if(user_choice == 1){
current->next=(node*)malloc(sizeof(node));
}
else{
current->next=NULL;
temp=current;
}
current=current->next;
}
return temp;
}
Please try with this
void *create(node *current)
{
int user_choice;
while(true){
if(current == NULL) {
current = (node *)malloc(sizeof(node));
current->data = NULL;
current->next = NULL;
}
printf("\nEnter the data:");
scanf("%s",current->data);
printf("stored at %p\n", (void *)current->data);
printf("%s",current->data);
//printf("%s",(char*)current->data);
printf("\nType '1' to continue, '0' to exit:\n");
scanf("%d",&user_choice);
if(user_choice == 1){
current->next=(node*)malloc(sizeof(node));
current=current->next;
}
else{
current->next=NULL;
tail = current;
current=current->next;
break;
}
}
return current;
}
Note: The element has to be initialized (ie; it has to be alloted with some memory) before we are trying to make use of it.

Resources