Why does the `search` function doesn't run? - c

I wrote a function to search nodes in a singly linked list. When I run it, it gets stuck while printing the node does or doesn't exist. There's no warning in the code so I am wondering if there's something wrong with my concept of function calls.
I know that curr->CharArr[9] shouldn't be in the function call, but what should I replace with it if I don't use it? Or is it actually acceptable?
This is the function call for searching nodes.
int search(struct LLNode *curr, char* find)
{
while (curr != NULL)
{
if (curr->CharArr[9] == find)
{
return 1;
curr = curr->next;
}
else if (curr->CharArr[9] != find)
{
return 0;
}
}
}
This is the code which calls it:
printf("\nEnter fruit name to search in the linked list: ");
scanf("%s", find);
int result = search(curr,&find);
if (result == 1)
{
printf("%s found in the list.\n", find);
}
else if (result == 0)
{
printf("%s not found in the list.\n", find);
}
And this is the whole function:
#include <stdio.h>
#include <stdlib.h>
struct LLNode
{
char *CharArr[10];
struct LLNode *next;
};
struct LLNode * createNode (char val[])
{
struct LLNode *temp;
temp =(struct LLNode *)malloc(sizeof(struct LLNode));
temp-> CharArr[9] = val;
temp-> next = NULL;
return (temp) ;
};
int search(struct LLNode *curr, char* find)
{
while (curr != NULL)
{
if (curr->CharArr[9] == find)
{
return 1;
curr = curr->next;
}
else if (curr->CharArr[9] != find)
{
return 0;
}
}
}
int main ()
{
struct LLNode *head = NULL;
struct LLNode *curr = NULL;
char find;
printf("The nodes are:\n");
head = curr = createNode ("Apple") ;
printf ("%s\n", curr->CharArr[9]) ;
curr = curr->next;
curr = createNode("Orange");
printf ("%s\n", curr->CharArr[9]) ;
printf("\nEnter fruit name to search in the linked list: ");
scanf("%s", find);
int result = search(curr,&find);
if (result == 1)
{
printf("%s found in the list.\n", find);
}
else if (result == 0)
{
printf("%s not found in the list.\n", find);
}
}

Your code has a lot of problem, that make your code not work:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct LLNode
{
char CharArr[10]; // problem 1: use array of char, not array of pointer of char
struct LLNode *next;
};
struct LLNode * createNode (const char* val)
{
struct LLNode *temp;
temp =(struct LLNode *)malloc(sizeof(struct LLNode));
strncpy(temp-> CharArr, val, 9); // problem 2: assign value to array
temp->CharArr[9] = 0; // be sure to make it null-terminated
temp-> next = NULL;
return (temp) ;
};
int search(struct LLNode *curr, char* find)
{
while (curr != NULL)
{
if (strncmp(curr->CharArr, find, 9) == 0) // problem 3: the way of comparing string
{
return 1; // problem 4: logic of `search` function. Need follow the logic: return 1 if found. You change `cur` pointer after return is do nothing
}
else
{
curr = curr->next; // move to next element if not found in current node
}
}
return 0; // return 0 if not found at all
}
int main ()
{
struct LLNode *head = NULL;
struct LLNode *curr = NULL;
char find[9] = {0};
printf("The nodes are:\n");
head = curr = createNode ("Apple") ;
printf ("%s\n", curr->CharArr) ;
curr->next = createNode("Orange"); // problem 5: assign wrong pointer for new element in linked list
printf ("%s\n", curr->next->CharArr) ;
printf("\nEnter fruit name to search in the linked list: ");
scanf("%s", find);
int result = search(head, find); // problem 6: pass `head` to search, not `curr`
if (result == 1)
{
printf("%s found in the list.\n", find);
}
else if (result == 0)
{
printf("%s not found in the list.\n", find);
}
}
The above code is sample of fix

I`m not really sure, but I think, first of all, I see unattainable code right here
...
if (curr->CharArr[9] == find)
{
return 1;
curr = curr->next; // right here, return statement before this line
}
...
If I'm not mistaken, in following code you want to compare two char arrays:
...
if (curr->CharArr[9] == find)
// some code
curr->CharArr[9] != find
...
but it does not work because you are using array subscript operator here curr->CharArr[9] and that`s just takes tenth symbol of the char array. If you need to compare two strings you need to compare each character of one string with the corresponding character of another string, or just use strcmp() function.

Firstly, the struct should be like this.
struct LLNode
{
char *CharArr;
struct LLNode *next;
};
The search function needs to use strcmp to match string and you should only return when a match is found.
int search(struct LLNode *curr, char* find)
{
while (curr != NULL)
{
if (strcmp(curr->CharArr, find) == 0)
return 1;
curr = curr->next;
}
return 0;
}
And in your main function, you need to pass in head to the search function. curr points to the latest node you inserted. And curr->next needs to be allocated first to have it be part of the linked list.
curr->next = createNode("Orange");
curr = curr->next;
printf ("%s\n", curr->CharArr) ;
printf("\nEnter fruit name to search in the linked list: ");
scanf("%s", find);
int result = search(head, find);

Related

Remove adjacent duplicates in linked list in C

As the title mentioned, I have to remove adjacent duplicates in linked list such that if input is 'google', output should be 'le'. I'm supposed to code it in C. I've written 70% of the code, except that I don't know how to continuously loop till all adjacent duplicates are removed. I'm removing adjacent duplicates in remove_adjacent_duplicates() function, and since I don't know how to put terminating condition in loop, I've merely used if-else loop. But my code in remove_adjacent_duplicates() function might contain mistakes, so please rectify it if any and please give solution to looping till all adjacent duplicates are removed. Here's my code-
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct node //node creation
{
char data;
struct node *next;
};
void remove_adjacent_duplicates(struct node** head_ref)
{
struct node* current = *head_ref;
struct node* cnext = NULL; //the one next to current one
int flag=0;
cnext = current->next; //storing next
//printf("%c %c %d\n",current->data,cnext->data,flag);
if(cnext->data==current->data)
{
flag=1;
while(cnext->data==current->data)
{
cnext=cnext->next;
}
current=cnext;
cnext = current->next; //storing next
}
else
{
current=current->next;
cnext = current->next; //storing next
}
//printf("%c %c %d\n",current->data,cnext->data,flag);
if(flag) *head_ref = current;
}
void push(struct node** head_ref, char new_data)
{
struct node* new_node = (struct node*)malloc(sizeof(struct node));
new_node->data = new_data;
new_node->next = *head_ref;
*head_ref = new_node;
}
void printList(struct node* head)
{
if (head == NULL)
{
printf("NULL\n\n");
return;
}
printf("%c->",head->data);
printList(head->next);
}
int main()
{
char s[100];
int i;
struct node* a = NULL;
printf("Enter string: ");
scanf("%s",s);
for(i=strlen(s)-1;i>-1;i--){
push(&a, s[i]); //last in first out, so in reverse g is last but first to come out
}
printf("\nConverting string to linked list: \n");
printList(a);
//printf("%c",current->data); prints first letter of a
remove_adjacent_duplicates(&a);
printList(a);
return 0;
}
You could use recursion. That way you can check whether before the recursive call or after the recursive call there is something to remove:
void remove_adjacent_duplicates(struct node** head_ref)
{
struct node* current = *head_ref;
if (current == NULL || current->next == NULL) return;
int isEqual = current->data == current->next->data;
remove_adjacent_duplicates(&current->next);
if (current->next != NULL && current->data == current->next->data) {
// Duplicates! Remove pair
*head_ref = current->next->next;
free(current->next);
free(current);
} else if (isEqual) {
// Continue ongoing removal
*head_ref = current->next;
free(current);
}
}
A few issues ...
The first element of list (e.g. head) can never be a duplicate
The code leaks memory when removing a dup because it doesn't do free
The code only removes the first element.
The code uses next, cur, but not previous, so the algorithm needs refactoring.
Casting the return of malloc is bad. See: Do I cast the result of malloc?
scanf is problematic. %s can overrun the end of the array. Better to use (e.g.) %99s [or better yet: fgets].
Here is the refactored code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
// node definition
struct node {
char data;
struct node *next;
};
void
remove_adjacent_duplicates(struct node **head_ref)
{
struct node *prev = *head_ref;
struct node *cur;
struct node *next;
// NOTE: first node can _never_ be a dup
if (prev != NULL)
cur = prev->next;
else
cur = NULL;
for (; cur != NULL; cur = next) {
// remember this in case we remove cur to prevent "use after free" bug
// when advancing cur
next = cur->next;
// remove duplicate
if (cur->data == prev->data) {
prev->next = next;
free(cur);
continue;
}
// point to last non-dup node
prev = cur;
}
}
void
push(struct node **head_ref, char new_data)
{
// NOTE/BUG: casting the result of malloc is bad
#if 0
struct node *new_node = (struct node *) malloc(sizeof(struct node));
#else
struct node *new_node = malloc(sizeof(*new_node));
#endif
new_node->data = new_data;
new_node->next = *head_ref;
*head_ref = new_node;
}
void
printList(struct node *head)
{
if (head == NULL) {
printf("NULL\n\n");
return;
}
printf("%c->", head->data);
printList(head->next);
}
int
main(void)
{
char s[100];
int i;
struct node *a = NULL;
printf("Enter string: ");
// NOTE/BUG: scanf is bad -- it can overrun the end of s
#if 0
scanf("%s", s);
#else
scanf("%99s", s);
#endif
// last in first out, so in reverse g is last but first to come out
for (i = strlen(s) - 1; i > -1; i--) {
push(&a, s[i]);
}
printf("\nConverting string to linked list: \n");
printList(a);
// printf("%c",current->data); prints first letter of a
remove_adjacent_duplicates(&a);
printList(a);
return 0;
}
In the above code, I've used cpp conditionals to denote old vs. new code:
#if 0
// old code
#else
// new code
#endif
#if 1
// new code
#endif
Note: this can be cleaned up by running the file through unifdef -k
UPDATE:
From the OP: "[ .. ] 'google', output should be 'le'.". Looks like both nodes are removed, and the effect compounds. –
Oka
Yes, it's much more complex. But, here is a version that removes all duplicates. I had some trouble myself, so I left in the debugging code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#if DEBUG
#define dbgprt(_fmt...) \
printf(_fmt)
#else
#define dbgprt(_fmt...) \
do { } while (0)
#endif
// node definition
struct node {
char data;
#if DEBUG
int seq;
#endif
struct node *next;
};
#if DEBUG
int seq = 0;
#endif
void
remove_adjacent_duplicates(struct node **head_ref)
{
struct node *prev = *head_ref;
struct node *cur;
struct node *next;
// NOTE: first node can _never_ be a dup
if (prev != NULL)
cur = prev->next;
else
cur = NULL;
for (; cur != NULL; cur = next) {
// remember this in case we remove cur to prevent "use after free" bug
// when advancing cur
next = cur->next;
// remove duplicate
if (cur->data == prev->data) {
prev->next = next;
free(cur);
continue;
}
// point to last non-dup node
prev = cur;
}
}
void
remove_all_duplicates(struct node **head_ref)
{
struct node *oldhead = *head_ref;
struct node *addprev = NULL;
struct node *addnext;
// loop through all candidate nodes
for (struct node *addcur = oldhead; addcur != NULL; addcur = addnext) {
int dupflg = 0;
// start of search for duplicates to the right of the candidate
struct node *prevdup = NULL;
struct node *dupcur = addcur->next;
// find all duplicates to the right [towards tail] of candidate node
while (1) {
// find first duplicate to the right of candidate [if one exists]
struct node *dupnext = NULL;
for (; dupcur != NULL; dupcur = dupnext) {
dupnext = dupcur->next;
if (dupcur->data == addcur->data) {
dupflg = 1;
break;
}
prevdup = dupcur;
}
// no more duplicates to the right of current candidate
if (dupcur == NULL)
break;
// remove a duplicate on the right
if (prevdup != NULL)
prevdup->next = dupnext;
else
addcur->next = dupnext;
free(dupcur);
}
addnext = addcur->next;
// remove candidate because it's a dup
if (dupflg) {
if (addprev != NULL)
addprev->next = addnext;
else
oldhead = addnext;
free(addcur);
continue;
}
// remember last valid non-dup node
addprev = addcur;
}
*head_ref = oldhead;
}
void
push(struct node **head_ref, char new_data)
{
// NOTE/BUG: casting the result of malloc is bad
#if 0
struct node *new_node = (struct node *) malloc(sizeof(struct node));
#else
struct node *new_node = malloc(sizeof(*new_node));
#endif
new_node->data = new_data;
#if DEBUG
new_node->seq = seq++;
#endif
new_node->next = *head_ref;
*head_ref = new_node;
}
void
printList(struct node *head)
{
if (head == NULL) {
printf("NULL\n\n");
return;
}
#if DEBUG
printf("%c%d->", head->data, head->seq);
#else
printf("%c->", head->data);
#endif
printList(head->next);
}
int
main(int argc,char **argv)
{
char s[100];
int opt_a = 0;
int i;
struct node *a = NULL;
--argc;
++argv;
for (; argc > 0; --argc, ++argv) {
char *cp = *argv;
if (*cp != '-')
break;
switch (cp[1]) {
case 'a':
opt_a = ! opt_a;
break;
}
}
printf("Enter string: ");
// NOTE/BUG: scanf is bad -- it can overrun the end of s
#if 0
scanf("%s", s);
#else
fflush(stdout);
if (fgets(s,sizeof(s),stdin) == NULL)
s[0] = 0;
s[strcspn(s,"\n")] = 0;
#endif
// last in first out, so in reverse g is last but first to come out
for (i = strlen(s) - 1; i > -1; i--)
push(&a, s[i]);
printf("\nConverting string to linked list: \n");
printList(a);
// printf("%c",current->data); prints first letter of a
if (opt_a)
remove_adjacent_duplicates(&a);
else
remove_all_duplicates(&a);
printList(a);
return 0;
}
UPDATE:
As for your code I can't understand it properly especially those # statements since I'm just an average coder in C with no advanced knowledge. –
New
The # lines aren't really advanced coding. They are C preprocessor (i.e. cpp) directives, similar to #define, #ifdef, #ifndef, and #endif. See the compiler manpage and/or man cpp.
They include/eliminate code at compile time in a separate first stage of the compilation process (i.e. the cpp stage).
Otherwise, the code is well commented to explain the intent of what the code is doing.
Side note: When I was first learning to code, in addition to school assignments, I was looking at some complex OS kernel code [in assembly language]. I just kept going over it, sometimes adding my own comments, until I did understand it. I learned more by reading and understanding such code than I did from most assignments.
At the bottom of my answer: What is the error in this code that checks if the linklist is a palindrome or not? is a list of resources I recommend.
Here is a cleaned up version of the my code above that eliminates the conditional cpp directives:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
// node definition
struct node {
char data;
struct node *next;
};
void
remove_adjacent_duplicates(struct node **head_ref)
{
struct node *prev = *head_ref;
struct node *cur;
struct node *next;
// NOTE: first node can _never_ be a dup
if (prev != NULL)
cur = prev->next;
else
cur = NULL;
for (; cur != NULL; cur = next) {
// remember this in case we remove cur to prevent "use after free" bug
// when advancing cur
next = cur->next;
// remove duplicate
if (cur->data == prev->data) {
prev->next = next;
free(cur);
continue;
}
// point to last non-dup node
prev = cur;
}
}
void
remove_all_duplicates(struct node **head_ref)
{
struct node *oldhead = *head_ref;
struct node *addprev = NULL;
struct node *addnext;
// loop through all candidate nodes
for (struct node *addcur = oldhead; addcur != NULL; addcur = addnext) {
int dupflg = 0;
// start of search for duplicates to the right of the candidate
struct node *prevdup = NULL;
struct node *dupcur = addcur->next;
// find all duplicates to the right [towards tail] of candidate node
while (1) {
// find first duplicate to the right of candidate [if one exists]
struct node *dupnext = NULL;
for (; dupcur != NULL; dupcur = dupnext) {
dupnext = dupcur->next;
if (dupcur->data == addcur->data) {
dupflg = 1;
break;
}
prevdup = dupcur;
}
// no more duplicates to the right of current candidate
if (dupcur == NULL)
break;
// remove a duplicate on the right
if (prevdup != NULL)
prevdup->next = dupnext;
else
addcur->next = dupnext;
free(dupcur);
}
addnext = addcur->next;
// remove candidate because it's a dup
if (dupflg) {
if (addprev != NULL)
addprev->next = addnext;
else
oldhead = addnext;
free(addcur);
continue;
}
// remember last valid non-dup node
addprev = addcur;
}
*head_ref = oldhead;
}
void
push(struct node **head_ref, char new_data)
{
struct node *new_node = malloc(sizeof(*new_node));
new_node->data = new_data;
new_node->next = *head_ref;
*head_ref = new_node;
}
void
printList(struct node *head)
{
if (head == NULL) {
printf("NULL\n\n");
return;
}
printf("%c->", head->data);
printList(head->next);
}
int
main(int argc,char **argv)
{
char s[100];
int opt_a = 0;
int i;
struct node *a = NULL;
--argc;
++argv;
for (; argc > 0; --argc, ++argv) {
char *cp = *argv;
if (*cp != '-')
break;
switch (cp[1]) {
case 'a':
opt_a = ! opt_a;
break;
}
}
printf("Enter string: ");
fflush(stdout);
if (fgets(s,sizeof(s),stdin) == NULL)
s[0] = 0;
s[strcspn(s,"\n")] = 0;
// last in first out, so in reverse g is last but first to come out
for (i = strlen(s) - 1; i > -1; i--)
push(&a, s[i]);
printf("\nConverting string to linked list: \n");
printList(a);
// printf("%c",current->data); prints first letter of a
if (opt_a)
remove_adjacent_duplicates(&a);
else
remove_all_duplicates(&a);
printList(a);
return 0;
}

I set head to be something but it is always null

I am simply just trying to print out my doubly linked list. However, even though I clearly set my head and tail to something, it is always NULL when I print it in main. I am unsure on what the issue is. I've tried to simplify the code as much as I can.
In the function grade_word_gen you can clearly see I set head to something and I set tail to something.
test.txt
*A*
Great
Fantastic
Lovely
*B*
Bad
Not Good
Terrible
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct grade {
struct grade_word *A_head;
struct grade_word *A_tail;
struct grade_word *B_head;
struct grade_word *B_tail;
};
struct grade_word {
char *word;
struct grade_word *next;
struct grade_word *prev;
};
struct grade *create_grade() {
struct grade *new_grade = malloc(sizeof(struct grade));
// Check grade was allocated correctly
if (new_grade == NULL) {
fprintf(stderr, "ERROR: Could not allocate memory for grade\n");
exit(1);
}
// Initialise all variables
new_grade->A_head = NULL;
new_grade->A_tail = NULL;
new_grade->B_head = NULL;
new_grade->B_tail = NULL;
return new_grade;
}
struct grade_word *create_grade_word(char *word) {
struct grade_word *new = malloc(sizeof(struct grade_word));
if (new == NULL) {
fprintf(stderr, "ERROR: Unable to allocate memory for grade_words\n");
exit(1);
}
// Initialise vairables
int len = strlen(word);
new->word = malloc(sizeof(char) * (len + 1));
strcpy(new->word, word);
new->next = NULL;
new->prev = NULL;
return new;
}
void grade_word_gen(struct grade *grade_data) {
FILE *fp = fopen("test.txt", "r");
char grade;
char buf[100 + 1];
struct grade_word *new_node;
struct grade_word *head;
struct grade_word *tail;
while (fgets(buf, 100, fp) != NULL) {
if (buf[0] == '*' && buf[2] == '*') {
grade = buf[1];
} else {
new_node = create_grade_word(buf);
// Set next, prev, head, tail pointers
if (grade == 'A') {
head = grade_data->A_head;
tail = grade_data->A_tail;
} else {
head = grade_data->B_head;
tail = grade_data->B_tail;
}
// If first item set the head
if (head == NULL) {
head = new_node;
//printf("head: %s\n", head->word);
// Otherwise just add on to the list
} else {
new_node->prev = tail;
tail->next = new_node;
}
tail = new_node;
}
// Reset buffer
strcpy(buf, "\0");
}
}
void print_grade_list(struct grade_word *list, char grade) {
if (list == NULL) {
printf("Grade %c is empty, so not grade words can be printed\n", grade);
return;
}
printf("Grade: %c\n", grade);
while (list != NULL) {
printf("%s\n", list->word);
list = list->next;
}
}
int main(void) {
struct grade *new_grade = create_grade();
grade_word_gen(new_grade);
print_grade_list(new_grade->A_head, 'A');
print_grade_list(new_grade->B_head, 'B');
}
My output is always Grade %c is empty, so not grade words can be printed. I don't understand why my head is always null, even though I do set it.
You never assign anything to A_head except in the initialization part where you assign NULL. Consequently A_head will remain at NULL:
The problem is here:
if (grade == 'A') {
head = grade_data->A_head; // Here you make head equal A_head
tail = grade_data->A_tail;
} else {
head = grade_data->B_head;
tail = grade_data->B_tail;
}
// If first item set the head
if (head == NULL) {
head = new_node; // Here you try to save new_node.
// But you save it into head and that will not
// change A_head
You need to have code like:
grade_data->A_head = new_node;
so that you actually change A_head.
An alternative way so that you can share the code between case A and B is double pointers. Like:
// Make a double pointer
struct grade_word **head;
. . .
// Make it point to either the A or B head pointer
head = &grade_data->A_head; // or head = &grade_data->B_head;
. . .
// Change A or B head pointer using head
*head = new_node;

Linked List making segmentation fault

Below I have made a simple Linked List in C. The code is currently producing a segmentation fault which I find odd because I was copying an example from our current book. The only thing I did to the code was put the code into the method "addToList". I'm aware the segmentation fault is coming from the method addToList but I do not know where I made a mistake.
#include <stdio.h>
#include <stdlib.h>
typedef struct node {
int val;
struct node *next;
} Node;
void addToList(Node *, int);
void printList(Node *);
void main() {
int x;
Node *head = malloc(sizeof(Node));
for (x = 1; x < 4); x++) {
printf("Enter an integer: ");
x = scanf("%d");
addToList(head, x);
}
printList(head);
}
void addToList(Node *head, int val) {
Node *current = head;
while (current->next != NULL) {
current = current->next;
}
current->next = malloc(sizeof(Node));
current->next->val = val;
current->next->next = NULL;
}
void printList(Node *head) {
Node *current = head;
while (current != NULL) {
printf("%d->", current->val);
current = current->next;
}
printf("\n");
}
Any help with telling me what is wrong or where I'm making the mistake would be greatly appreciated.
Look carefully at your code:
int main(void) {
int x;
Node *head = malloc(sizeof(Node));
for (x = 1; x < 4); x++) {
...
addToList(head, x);
}
...
}
You are not initializing the memory, so head->val and head->next are not
initialized. Because of that
while (current->next != NULL) {
current = current->next;
}
will loop an undefined amount of times. The first current->next is most
probably not NULL, so current = current->next get executed. At that point current is pointing to nowhere, hence the undefined behaviour which in your case leads to a segfault.
You have to initialized the memory like this:
Node *head = malloc(sizeof *head);
if(head == NULL)
// error handling
head->next = NULL;
But you could also use calloc, which also sets the memory to 0, thus you don't have to initialize the values (in this case):
Node *head = calloc(1, sizeof *head);
if(head == NULL)
// error handling
You should always check for the return value of malloc/calloc/realloc.
Also note that the signature of the main function can be one of these:
int main(void);
int main(int argc, char **argv);
int main(int argc, char *argv[]);
edit
Another error I've noticed right now:
x = scanf("%d");
That's not how scanf works. You have to pass a pointer, scanf saves the
scanned value through the passed pointer. scanf returns the number of matched
values on success, in this case, success would be 1:
int num;
int ret = scanf("%d", &num);
if(ret != 1)
{
fprintf(stderr, "Could not read value from the user\n");
continue; // to contiune looping
// you could also do a break; and stop the looping, or
// exit(1), etc.
}
// error with scanf
Also don't use the same variable x for the loop iteration and user input,
otherwise you are messing with the loop.
edit
User user3629249 wrote in the comment
good information, however the result will be the first entry in the linked list will contain garbage.
Better to declare head via: Node *head = NULL; and the function addToList() check for NULL and proceed accordingly.
That's right, the head element doesn't save any number in this way.
Option 1: double pointer
Here addToList receives a double pointer. The initialization of head occurs
when *head points to NULL. The function allocates memory for it, initializes
the memory, saves the value and returns. In the concurrent calls of addToList
*head won't be NULL, so addToList looks for the end of the list.
I've made small changes in the way you do malloc and realloc. Also I added
an implementation of freeList which should be used to free the memory:
void addToList(Node **head, int val) {
if(head == NULL)
{
fprintf(stderr, "head cannot be NULL\n");
return;
}
if(*head == NULL)
{
*head = calloc(1, sizeof **head);
head[0]->val = val;
head[0]->next = NULL;
return;
}
Node *current = *head;
while (current->next != NULL) {
current = current->next;
}
current->next = malloc(sizeof *current->next);
if(current->next == NULL)
return;
current->next->val = val;
current->next->next = NULL;
}
int main(void)
{
int x;
Node *head = NULL;
for (x = 1; x < 4; x++)
{
int val;
printf("Enter an integer: ");
if(scanf("%d", &val) != 1)
{
fprintf(stderr, "Could not read from user. Skipping entry\n");
continue;
}
addToList(&head, val);
}
printList(head);
freeList(head);
return 0;
}
void freeList(Node *head)
{
if(head == NULL)
return;
Node *current = head;
Node *next;
while(next = current->next)
{
free(current);
current = next;
}
free(current); // the last one
free(head);
}
Option 2: addToList returns a pointer to the head
Here addToList takes a pointer to the head. If it's NULL, it allocates
memory and initializes like in the shown above. If head is not NULL, the
functions looks for the last element and the returns the head. On error the
function returns NULL.
Node *addToList(Node *head, int val) {
if(head == NULL)
{
head = calloc(1, sizeof **head);
head->val = val;
head->next = NULL;
return head;
}
Node *current = *head;
while (current->next != NULL) {
current = current->next;
}
current->next = malloc(sizeof *current->next);
if(current->next == NULL)
return NULL;
current->next->val = val;
current->next->next = NULL;
return head;
}
int main(void)
{
int x;
Node *head = NULL, *tmp;
for (x = 1; x < 4; x++)
{
int val;
printf("Enter an integer: ");
if(scanf("%d", &val) != 1)
{
fprintf(stderr, "Could not read from user. Skipping entry\n");
continue;
}
tmp = addToList(head, val);
if(tmp == NULL)
{
fprintf(stderr, "Not enough memory\n");
freeList(head);
return 1;
}
head = tmp;
}
printList(head);
freeList(head);
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.

linked list insertion at end when header node is not null

I'm having a problem with inserting a node at the end of a linked list. It's not being executed when the start node is not null and I don't understand the problem. Please help me out here. The function is called second time but is not going to the else block.
typedef struct token_Info
{
int linenumber;
char* token;
char value[200];
struct token_Info* next;
} token_Info;
token_Info *tokenlist;
token_Info* insert_at_end( token_Info *list,char *name)
{
printf("token identified \t");
token_Info *new_node;
token_Info *temp,*start;
start = list ;
char *tempname ;
tempname = name;
new_node= malloc(sizeof(token_Info));
new_node->token = malloc(sizeof(strlen(tempname)+1));
strcpy(new_node->token,tempname);
new_node->next= NULL;
// printf("%d",strlen(tempname));
if(new_node == NULL){
printf("nFailed to Allocate Memory");
}
if(start==NULL)
{
start=new_node;
return start;
}
else
{
printf("anvesh");
temp = start;
while(temp->next != NULL)
{
temp = temp ->next;
}
temp->next = new_node;
return temp;
}
}
tokenlist = insert_at_end(tokenlist,"TK_BEGIN");
tokenlist = insert_at_end(tokenlist,"TK_BEGIN1");
UPDATE
I found two bugs, the first was the head of the list was not being returned when appending the list. The other in the memory allocation for the token string which incorrectly used sizeof.
I repositioned the test of the malloc() return value, and added a second one. I removed several unnecessary temporary variables that were cluttering the code. I added two functions, show_list() and free_list(). Finally, remember that the value string field is still uninitialised.
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
typedef struct token_Info
{
int linenumber;
char* token;
char value[200];
struct token_Info* next;
} token_Info;
token_Info* insert_at_end( token_Info *list, char *name)
{
token_Info *new_node, *temp;
new_node= malloc(sizeof(token_Info));
if(new_node == NULL){ // repositioned
printf("\nFailed to allocate node memory\n");
exit(1); // added
}
new_node->token = malloc(strlen(name)+1); // removed sizeof
if(new_node->token == NULL){ // added
printf("\nFailed to allocate token memory\n");
exit(1);
}
strcpy(new_node->token, name);
new_node->next= NULL;
if(list==NULL)
return new_node;
// append
temp = list;
while(temp->next != NULL)
temp = temp->next;
temp->next = new_node;
return list; // original head
}
void free_list( token_Info *list)
{
token_Info *temp;
while (list) {
temp = list->next;
free(list->token);
free(list);
list = temp;
}
}
void show_list( token_Info *list)
{
printf ("\nCurrent list:\n");
while (list) {
printf ("%s\n", list->token);
list = list->next;
}
}
int main(int argc, char **argv)
{
token_Info *tokenlist = NULL;
tokenlist = insert_at_end(tokenlist, "TK_BEGIN");
show_list(tokenlist);
tokenlist = insert_at_end(tokenlist, "TK_SECOND");
show_list(tokenlist);
tokenlist = insert_at_end(tokenlist, "TK_FINAL");
show_list(tokenlist);
free_list(tokenlist);
return 0;
}
Program output:
Current list:
TK_BEGIN
Current list:
TK_BEGIN
TK_SECOND
Current list:
TK_BEGIN
TK_SECOND
TK_FINAL
The question could also be whether you want tokenlist to be a running end of the list, or remain at the start.
As of right now, your first call:
tokenlist = insert_at_end(tokenlist,"TK_BEGIN");
has tokenlist being the only node in the list.
The second call tokenlist = insert_at_end(tokenlist,"TK_BEGIN1"); returns 'temp' which happens to also be the 'TK_BEGIN' node, ( ie, the first node )
If you want the return value to be the last element, you would return new_node instead of temp. If you want to retain the start, you would return start;
All that said:
The calls to it are not part of any function,
I just ran it with the calls in main and got this output:
int main(void){
tokenlist = insert_at_end(tokenlist,"TK_BEGIN");
tokenlist = insert_at_end(tokenlist,"TK_BEGIN1");
return 0;
}
$> ./a.out
token identified token identified anvesh

Resources