I set head to be something but it is always null - c

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;

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;
}

Return a pointer from a function, then free the pointer

Im trying to process multiple names from the command line argv[] and then add or remove said names if they were prefaced by a '+' or '-'. IE +bill +ted -ted would add bill and ted then remove ted. I can add names to this list no problem but my removeNode() function call results in a segmentation fault. In my main() when I go to process names to be removed I set char * name to be equal to the return pointer of removeNode(), which should be the string from the node being freed. What would the correct way to return this pointer be so I can remove the name I reference from the command line? Ive also included my insert function.
int insert(struct node ** head, char * name) {
struct node * newNode = (struct node * ) malloc(sizeof(struct node));
newNode -> data = name;
newNode -> next = NULL;
struct node * current = * head;
if ( * head == NULL) {
* head = newNode;
return 1;
}
while (current -> next != NULL) {
current = current -> next;
}
current -> next = newNode;
return 1;
}
char * removeNode(struct node ** head, char * name) {
struct node * current = * head;
struct node * previous;
if (current == NULL) {
return "error0";
}
if (strcmp(current -> data, name) == 0) {
char * data = current -> data;
* head = current -> next;
free(current);
printf("Removed %s \n", name);
return data;
}
while (current != NULL) {
previous = current;
current = current -> next;
if (strcmp(current -> data, name) == 0) {
char * data = current -> data;
previous -> next = current -> next;
free(current);
printf("Removed %s \n", name);
return data;
}
}
return "error0";
}
int main(int argc, char * argv[]) {
printf("Author : Torin Costales \n");
struct node * head = NULL;
for (int x = 1; x < argc; x++) {
if (argv[x][0] == '+') {
char * name = malloc((strlen(argv[x] + 1) + 1));
if (name == NULL) return EXIT_FAILURE;
strcpy(name, argv[x]);
printf("adding %s \n", name);
insert( & head, name);
printf("List: ");
printList( & head);
} else if (argv[x][0] == '-') {
printf("removing %s \n", argv[x] + 1);
char * name = removeNode( & head, argv[x] + 1);
free(name);
printList( & head);
}
}
}
The problem leading the to fault is that you were using
strcpy(name, argv[x]);
where you should have been using
strcpy(name, argv[x] + 1);
This caused a string produced by "error0" to be returned when trying to remove ted since the list contained +bill and +ted.
Fixed and cleaned up:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct node {
char *data;
struct node *next;
} node;
void printList(struct node *node) { // Don't need a pointer to a pointer.
printf("List:");
for (; node; node = node->next)
printf(" %s", node->data);
printf("\n");
}
// Returns 0 on success.
// Returns -1 and sets errno on error.
int append(struct node **node_pp, char *name) { // Better name
while (*node_pp)
node_pp = &( (*node_pp)->next );
struct node *newNode = malloc(sizeof(struct node));
if (!newNode)
return -1;
newNode->data = name;
newNode->next = NULL;
*node_pp = newNode;
return 0;
}
// Returns NULL if not found.
char *removeNode(struct node **node_pp, const char *name) { // Added `const`
for (; *node_pp; next_p = &( (*node_pp)->next )) {
if (strcmp((*node_pp) -> data, name) == 0) {
struct node * oldNode = *next_p;
*node_pp = oldNode->next;
char *data = oldNode->data;
free(oldNode);
return data;
}
}
return NULL; // NULL is a far better value to return on error.
}
int main(int argc, char * argv[]) {
struct node *head = NULL;
for (int x = 1; x < argc; x++) {
if (argv[x][0] == '+') {
char *name = strdup(argv[x] + 1); // Simpler
if (name == NULL) {
perror("Can't allocate memory"); // Error message is good
exit(EXIT_FAILURE);
}
printf("Appending %s.\n", name);
if (append(&head, name) < 0) {
perror("Can't append node to list");
exit(EXIT_FAILURE);
}
} else if (argv[x][0] == '-') {
const char *name_to_find = argv[x] + 1;
printf("Removing %s.\n", name_to_find);
char *name = removeNode(&head, name_to_find);
if (name) { // Do check if it was found!
free(name);
} else {
printf("%s not found\n", name_to_find);
}
}
printList(head);
printf("\n");
}
}
Output for +foo +bar -baz -foo:
Appending foo.
List: foo
Appending bar.
List: foo bar
Removing baz.
baz not found
List: foo bar
Removing foo.
List: bar

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

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);

Adding a char array to a linked list

#include <stdio.h>
#include <stdlib.h>
typedef struct node{
char word[20];
struct node * next;
}node;
int main(){
FILE *ifp;
char newword[20];
node * head;
ifp = fopen("para.txt","r");
head = (node * )malloc(sizeof(node));
while(fscanf(ifp,"%s",newword) != EOF){
head -> next = NULL;
head -> word = newword;
}
return 0;
}
I want to add the words which is read by the text file to a link list. I tried to do with this code but I couldn't. How can I fix this.
You only allocate one node (head) and then change its contents each iteration of the loop. To create a linked list, you need to allocate a new node for each word (each iteration of the loop). Something like this should do it:
int main(){
FILE *ifp;
char newword[20];
node * head = NULL;
node *last = NULL;
node *current;
ifp = fopen("para.txt","r");
if (ifp == NULL) {
fprintf(stderr, "Unable to open file para.txt\n");
return EXIT_FAILURE;
}
while(fscanf(ifp,"%19s",newword) != EOF){
current = malloc(sizeof(node));
strcpy(current -> word,newword);
if(last) {
last->next = current;
}
else {
head = current;
}
last = current;
}
return EXIT_SUCCESS;
}
Keep track of a head and tail, or just push at head. The following appends to end, efficiently.
#include <stdio.h>
#include <stdlib.h>
typedef struct node{
struct node * next;
char word[1];
//or, char word[20];//fixed length word
}node;
node*
nodeNew(char* word) {
if(!word) return NULL;
//either dynamically allocate for strlen(word)
node* pnode = malloc( sizeof(node)+strlen(word) );
//or fixed len word
if( pnode ) {
pnode->next = NULL;
strcpy(pnode->word, word);
//or, strncpy(pnode->word, word, 20-1); //fixed length
}
return pnode;
}
int main()
{
FILE *ifp;
char newword[200]; //since using fscanf, need to avoid buffer overflow, should use fgets and strtok instead
node * head;
if( !(ifp = fopen("para.txt","r") ) { printf("error\n"); exit(0); }
head = NULL;
while(fscanf(ifp,"%s",newword) != EOF){
if( !head ) { tail = head = nodeNew(newword); }
else { tail->next = nodeNew(newword);
}
//head points to first element, head->next points to next element
//tail points to last element
return 0;
}

FILE reading and sorting a link list

It seems my FILE reading function is slightly off. Instead of printing all the data (First Name: Last Name: priority: Reading Level:) per entry when I call my print function it stops after two and just has the skeleton of what needs to be printed there for the last three entries. And because of that, when I then call my sort function based off priority level in each struct link list, I can't tell if it's printing correctly.
#include <stdlib.h>
#include <stdbool.h>
#include <stdio.h>
#define NAME 25
#define TITLE 50
typedef struct Book{
int bookID;
char* title;
bool checkedOut;
struct Book* next;
}book;
typedef struct Student{
char* firstName;
char* lastName;
int priority;
int readingLevel;
book* backPack;
bookids* wishlist;
struct Student* next;
}student;
student* buildStudentList(char* studentFile, student* head)
{
FILE *cfptr=fopen(studentFile, "r");
if(cfptr==NULL){
printf("\nFIle could not be opened\n");
return 0;
}
if(head==NULL){
head=malloc(sizeof(student));
head->next=NULL;
head->firstName=malloc(sizeof(student)*35);
head->lastName=malloc(sizeof(student)*35);
fscanf(cfptr,"%s %s %d %d", head->firstName,head->lastName,
&head->priority, &head->readingLevel);
}
student* current=head;
while(current->next!=NULL){
current=current->next;
}
current->next=malloc(sizeof(student));
current=current->next;
current->firstName=malloc(sizeof(student)*35);
current->lastName=malloc(sizeof(student)*35);
while( fscanf(cfptr, "%s %s %d %d", current->firstName, current->lastName,
&current->priority, &current->readingLevel)!=EOF){
student* current=head;
while(current->next!=NULL){
current=current->next;
}
current->next=malloc(sizeof(student));
current=current->next;
current->firstName=malloc(sizeof(student)*35);
current->lastName=malloc(sizeof(student)*35);
}
return head;
}
void createPriorityQueue(student* head)
{
if(head==NULL ||head->next==NULL){
return;
}
student* curr; student* largest; student* largestPrev; student* prev;
curr=head;
largest=head;
prev=head;
largestPrev=head;
while(curr!=NULL){
if(&curr->priority>&largest->priority){
largestPrev=prev;
largest=curr;
}
prev=curr;
curr=curr->next;
}
student* tmp;
if(largest!=head)
{
largestPrev->next=head;
tmp=head->next;
head->next=tmp;
}
}
There are a few bugs.
The malloc for allocation of strings should be malloc(35) and not malloc(sizeof(student) * 35). It won't crash but it's wasteful.
Your build function was way too complicated and had several bugs--I had to recode it.
Your priority queue function was comparing addresses of priority instead of values [what we want].
Anyway, here's your code with some annotations for the bugs and a recoded create function [please pardon the gratuitous style cleanup]:
#include <stdlib.h>
#include <stdbool.h>
#include <stdio.h>
#define NAME 25
#define TITLE 50
typedef struct Book {
int bookID;
char *title;
bool checkedOut;
struct Book *next;
} book;
typedef struct Student {
char *firstName;
char *lastName;
int priority;
int readingLevel;
book *backPack;
bookids *wishlist;
struct Student *next;
} student;
// NOTE/BUG: this function is way to complicated -- see below for a simpler one
student *
buildStudentList(char *studentFile, student * head)
{
FILE *cfptr = fopen(studentFile, "r");
if (cfptr == NULL) {
printf("\nFIle could not be opened\n");
return 0;
}
if (head == NULL) {
head = malloc(sizeof(student));
head->next = NULL;
// NOTE/BUG: we want just enough to store strings -- this is true for all the
// other mallocs that allocate names
#if 0
head->firstName = malloc(sizeof(student) * 35);
head->lastName = malloc(sizeof(student) * 35);
#else
head->firstName = malloc(35);
head->lastName = malloc(35);
#endif
fscanf(cfptr, "%s %s %d %d",
head->firstName, head->lastName, &head->priority,
&head->readingLevel);
}
student *current = head;
while (current->next != NULL) {
current = current->next;
}
current->next = malloc(sizeof(student));
current = current->next;
current->firstName = malloc(sizeof(student) * 35);
current->lastName = malloc(sizeof(student) * 35);
while (fscanf(cfptr, "%s %s %d %d",
current->firstName, current->lastName, &current->priority,
&current->readingLevel) != EOF) {
student *current = head;
while (current->next != NULL) {
current = current->next;
}
current->next = malloc(sizeof(student));
current = current->next;
current->firstName = malloc(sizeof(student) * 35);
current->lastName = malloc(sizeof(student) * 35);
}
// NOTE/BUG: close input file
#if 1
fclose(cfptr);
#endif
return head;
}
// simplified version
student *
buildStudentList(char *studentFile, student * head)
{
FILE *cfptr = fopen(studentFile, "r");
student *current;
student *tail;
char firstName[5000];
char lastName[5000];
if (cfptr == NULL) {
printf("\nFIle could not be opened\n");
return 0;
}
// find last element in list
tail = NULL;
for (current = head; current != NULL; current = current->next)
tail = current;
while (1) {
// allocate new node
current = malloc(sizeof(student));
// initialize the next pointer (in a singly linked list, this is nulled)
current->next = NULL;
// get data for new node
if (fscanf(cfptr, "%s %s %d %d",
firstName, lastName, &current->priority,
&current->readingLevel) == EOF) {
free(current);
break;
}
// allocate space for strings
current->firstName = strdup(firstName);
current->lastName = strdup(lastName);
// add to empty list
if (head == NULL)
head = current;
// add to tail of list
else
tail->next = current;
// set this as new tail of list
tail = current;
}
fclose(cfptr);
return head;
}
void
createPriorityQueue(student * head)
{
if (head == NULL || head->next == NULL) {
return;
}
student *curr;
student *largest;
student *largestPrev;
student *prev;
curr = head;
largest = head;
prev = head;
largestPrev = head;
while (curr != NULL) {
// NOTE/BUG: this compares _addresses_ but we want to compare values
#if 0
if (&curr->priority > &largest->priority) {
#else
if (curr->priority > largest->priority) {
#endif
largestPrev = prev;
largest = curr;
}
prev = curr;
curr = curr->next;
}
student *tmp;
if (largest != head) {
largestPrev->next = head;
tmp = head->next;
head->next = tmp;
}
}
UPDATE:
how do I make the createpriority function sort in the opposite order, its form highest to lowest, i need lowest to highest?
Not sure exactly which order you want now or what changes you've already made. In your original code, you were only doing a single pass on the list instead of as many passes as there were elements.
I've fixed the original code to do the correct number of passes, using simple insertion/selection. This is slow. You could speed it up by doing a mergesort on the linked list, but that's more involved.
Anyway, here's the code. I didn't test it or even compile it but it should get you closer:
student *
createPriorityQueue(student *head)
{
student *curr;
student *bestCurr;
student *bestPrev;
student *prev;
student *tail;
student *rtn;
// initialize sorted list
rtn = NULL;
tail = NULL;
// process all elements of unsorted list
while (head != NULL) {
// assume head of unsorted list is best priority in unsorted list
bestCurr = head;
bestPrev = NULL;
// find best in unsorted list
prev = NULL;
for (curr = head; curr != NULL; curr = curr->next) {
#ifdef SORT_LOW_TO_HIGH
if (curr->priority < bestCurr->priority) {
bestCurr = curr;
bestPrev = prev;
}
#else
if (curr->priority > bestCurr->priority) {
bestCurr = curr;
bestPrev = prev;
}
#endif
prev = curr;
}
// remove element from unordered list
if (bestPrev != NULL)
bestPrev->next = bestCurr->next;
else
head = bestCurr->next;
// add the next best priority to the end of the ordered list
if (tail != NULL)
tail->next = bestCurr;
else
rtn = bestCurr;
// set new tail of ordered list
tail = bestCurr;
tail->next = NULL;
}
return rtn;
}

Resources