Current node not resetting to head node it is referenced to - c

I have created 2 linked lists. Node and Codex. Codex is a spell checker.
Eye I
eye I
chequer checker
Pea P
Sea C
plane plainly
lee skip
four for
revue review
Miss Mistakes
Steaks skip
knot not
sea see
quays keys
whirred word
weight wait
Two To
two to
Weather Whether
write right
oar or
aweigh away
threw through
Your You're
shore sure
two to
no know
Its It's
vary very
weigh way
tolled told
sew so
bless blessed
freeze frees
yew you
lodes loads
thyme time
right write
stiles styles
righting writing
aides aids
rime rhyme
frays phrase
come composed
posed skip
trussed trusted
too to
bee be
joule jewel
cheque check
sum some
The other linked list is a text file of words. Looks like this.
Eye have a spelling chequer,
It came with my Pea Sea.
It plane lee marks four my revue,
Miss Steaks I can knot sea.
Eye strike the quays and type a whirred,
And weight four it two say,
Weather eye am write oar wrong,
It tells me straight aweigh.
Eye ran this poem threw it,
Your shore real glad two no.
Its vary polished in its weigh.
My chequer tolled me sew.
A chequer is a bless thing,
It freeze yew lodes of thyme.
It helps me right all stiles of righting,
And aides me when eye rime.
Each frays come posed up on my screen,
Eye trussed too bee a joule.
The chequer pours over every word,
Two cheque sum spelling rule.
Now when you find Eye in the data file, you would replace it with I. As you can see in the codex file they are right next to each other.
My code works when inserting the text into the linked lists. But when I pass the head of both linked lists to my function called LIST_CORRECT, the head node of the codex gets stuck at the node with the word sum(second to last word in codex). I have tried setting a pointer to both heads of the linked lists and make those currents but that still does not work. Any suggestions on what to do?
Here is the code.
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <string.h>
// A complete working C program to demonstrate all insertion methods
// on Linked List
// A linked list node
struct Node;
void push(struct Node **head_ref, char *new_data);
void insertAfter(struct Node *prev_node, char *new_data);
void append(struct Node **head_ref, char *new_data);
void printList(struct Node *node);
//void LIST_CORRECT(struct Codex **head_refC,struct Node **head_ref);
//void pushC(struct Codex **head_ref, char *new_data);
//void insertAfterC(struct Codex *prev_node, char *new_data);
//void appendC(struct Codex **head_ref, char *new_data);
//void printListC(struct Codex *node);
int LINECOUNT(FILE *(*stream), char *filename);
struct Node {
char *data;
struct Node *next;
};
struct Codex {
char *word1;
char *word2;
struct Codex *next;
};
/* Given a reference (pointer to pointer) to the head of a list and
an int, inserts a new node on the front of the list. */
void push(struct Node **head_ref, char *new_data) {
/* 1. allocate node */
struct Node* new_node = (struct Node *)malloc(sizeof(struct Node));
/* 2. put in the data */
new_node->data = new_data;
//printf("push data:%s ", new_data);
/* 3. Make next of new node as head */
new_node->next = (*head_ref);
/* 4. move the head to point to the new node */
(*head_ref) = new_node;
}
void pushC(struct Codex **head_ref, char *new_word,char *new_word2) {
/* 1. allocate node */
struct Codex* new_node = (struct Codex *)malloc(sizeof(struct Codex));
struct Codex* new_node2 = (struct Codex *)malloc(sizeof(struct Codex));
/* 2. put in the data */
new_node->word1 = new_word;
//printf("push data:%s ", new_data);
/* 3. Make next of new node as head */
new_node->next = (*head_ref);
/* 4. move the head to point to the new node */
(*head_ref) = new_node;
//------------------------//
/* 5. put in the data */
new_node2->word2 = new_word;
//printf("push data:%s ", new_data);
/* 6. Make next of new node as head */
new_node2->next = (*head_ref);
/* 7. move the head to point to the new node */
(*head_ref) = new_node2;
}
/* Given a reference (pointer to pointer) to the head
of a list and an int, appends a new node at the end */
// This function prints contents of linked list starting from head
void printListC(struct Codex *node) {
while (node != NULL) {
printf("%s ", node->word1);
node = node->next;
}
}
void LIST_INSERT_POEM(struct Node **head_ref, char *new_data) {
/* 1. allocate node */
struct Node* new_node = (struct Node *)malloc(sizeof(struct Node));
struct Node *last = *head_ref; /* used in step 5*/
/* 2. put in the data */
new_node->data = new_data;
//printf("push data:%s ", new_data);
/* 3. This new node is going to be the last node, so make next of
it as NULL*/
new_node->next = NULL;
/* 4. If the Linked List is empty, then make the new node as head */
if (*head_ref == NULL) {
*head_ref = new_node;
return;
}
/* 5. Else traverse till the last node */
while (last->next != NULL)
last = last->next;
/* 6. Change the next of last node */
last->next = new_node;
return;
}
void LIST_INSERT_CODEX(struct Codex **head_ref, char *new_data) {
/* 1. allocate node */
struct Codex* new_node = (struct Codex *)malloc(sizeof(struct Codex));
//if(x==1){
struct Codex *last = *head_ref; /* used in step 5*/
/* 2. put in the data */
new_node->word1 = new_data;
//printf("push data:%s ", new_data);
/* 3. This new node is going to be the last node, so make next of
it as NULL*/
new_node->next = NULL;
/* 4. If the Linked List is empty, then make the new node as head */
if (*head_ref == NULL) {
*head_ref = new_node;
return;
}
/* 5. Else traverse till the last node */
while (last->next != NULL)
last = last->next;
/* 6. Change the next of last node */
last->next = new_node;
return;
}
// This function prints contents of linked list starting from head
void printList(struct Node *node) {
while (node != NULL) {
printf("%s ", node->data);
node = node->next;
}
}
int LINECOUNT(FILE *(*stream), char *filename) {
int size = 0;
size_t chrCount;
char *text;
if ((*stream = fopen(filename, "r")) == NULL) {
printf("LC Could not open hw8 data file.\n");
exit(0);
}
while (1) {
text = NULL;
getline(&text, &chrCount, *stream);
free(text); /*free text*/
if (feof(*stream))
break;
size++;
}
rewind(*stream);
return size;
}
void LIST_CORRECT(struct Codex **head_refC,struct Node **head_ref,int lc,int x){
int t;int e;printf("\nlc for codex:%d\n",lc);
//struct Codex **currentC; struct Node **CurrentH;
struct Codex **currentC = (struct Codex **)malloc(sizeof(struct Codex*));
struct Node** currentH = (struct Node **)malloc(sizeof(struct Node*));
currentC=head_refC;
currentH=head_ref;
printf("\ncurrentC:%s\n",(*currentC)->word1);
printf("currentH:%s\n",(*currentH)->data);
t = strcmp( ((*currentC)->word1) , ((*currentH)->data) );
printf("t:%d\n",t);
if(t==0){printf("(t==0)");((*currentH)->data)=(((*currentC)->next)->word1);}
if(t!=0){for(int i = 0;i<lc-1;i++){printf("\ti:%d\tcurrentC:%s\t",i,(*currentC)->word1);(*currentC)=(*currentC)->next->next;printf("currentC:%s\n",(*currentC)->word1);}}
}
int main(void) {
char *fn = "hw8data.txt";
char *fn2 = "hw8codex.txt";
int lineCount;
int lineCount2;
FILE *stream;
FILE *stream2;
lineCount = LINECOUNT(&stream, fn);
lineCount2= LINECOUNT(&stream2,fn2);
//int lineArr[lineCount];
//int lineArr[];//lineArr[0] = 4 would say the first line has 4 words. using this data for strtok
//lineArr = wordCount(&stream, fn, lineCount);
//-------------------------------------
char ch;
int wordcount = 0;
int charcount = 0;
int wordcount2 = 0;
int charcount2 = 0;
stream = fopen("./hw8data.txt", "r");
int x = 0;
int lineArr[lineCount];
for (int i = 0; i < lineCount; i++) {
lineArr[i] = 0;
}
if (stream) {
while ((ch = getc(stream)) != EOF) {
if (ch != ' ' && ch != '\n') {
charcount++;
}
if (ch == ' ' || ch == '\n') {
wordcount++;
lineArr[x] = lineArr[x] + 1;
}
if (ch == '\n') {
x++;
}
}
printf("\nwc:%d\n",wordcount);
//if (charcount > 0) { wordcount++; charcount++; }
} else {
printf("Failed to open the file1\n");
}
//----------------------------------------------//
stream2 = fopen("./hw8codex.txt", "r");
int y = 0;
int lineArr2[lineCount2];
for (int i = 0; i < lineCount2; i++) {
lineArr2[i] = 0;
}
if (stream) {
while ((ch = getc(stream)) != EOF) {
if (ch != ' ' && ch != '\n') {
charcount2++;
}
if (ch == ' ' || ch == '\n') {
wordcount2++;
lineArr2[y] = lineArr2[y] + 1;
}
if (ch == '\n') {
y++;
}
}
//if (charcount > 0) { wordcount++; charcount++; }
} else {
printf("Failed to open the file2\n");
}
//----------------------------------------------//
/* Start with the empty list */
struct Node *head = NULL;
struct Codex *headC = NULL;
struct Node **headP = &head;
struct Codex **headCP = &headC;
printf("\n%p\t",&head); printf("%p\n",headP);
printf("\n%p\t",&headC); printf("%p\n",headCP);
rewind(stream);
rewind(stream2);
//char *sArr = malloc(42 * sizeof(char));
//printf("List-----------------------------\n\n");
for(int i =0; i<wordcount;i++){
char *sArr = malloc(42 * sizeof(char));
fscanf(stream, "%s ", sArr);
//printf("%s ", sArr);
LIST_INSERT_POEM(&head, sArr);
i++;
}
//printf("\n\nCodex-----------------------------\n\n");
char *sArr2 = malloc(42 * sizeof(char));
for(int i =0; i<lineCount2+lineCount2;i++){
char *sArr = malloc(42 * sizeof(char));
char *sArr2 = malloc(42 * sizeof(char));
fscanf(stream2, "%s %s", sArr,sArr2);
//printf("%s %s ", sArr,sArr2);
LIST_INSERT_CODEX(&headC, sArr);
LIST_INSERT_CODEX(&headC, sArr2);
i++;
}
//printf("\n\n-----------------------------\n\n");
printListC(headC);
printf("\n\n");
printf("head->data:%s\theadC->word1:%s",(head)->data,(headC)->word1);
for(int i = 0;i<wordcount;i++){
printf("\nLIST_CORRECT CALL #%d\n",i+1);
//LIST_CORRECT(&headC,&head,lineCount2,i);
LIST_CORRECT(*(&headCP),*(&headP),lineCount2,i);
printf("head->data:%s\theadC->word1:%s",(head)->data,(headC)->word1);
}
printList(head);
return 0;
}

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

C linked list problem, segfault when printing the list to a file

I'm trying to write and use linked list. When trying to print the list to the file the first string gets chained to the last node and it causes a segfault.
I've tried debugging and it led me nowhere.
It only happens using printListToFile(...) and readstl(...).
The code
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "lists_c.h"
#define test "ijm digidimdimadam jjsklva /s4t\t \nmjam \nla kookaracha la kookaracha\n"
/*a method that creates a "blank" node, declares a the next node and points it to NULL, the char array is already initialized.*/
struct Node *makeNode();
struct Node *makeFullNode(struct Node *Next, char *Ptr);
struct Node *readFile(char *path);
struct Node *readstl(char*);
void printList(struct Node *head);
void insertToList(struct Node *node, char *str);
void printListToFile(char *path, struct Node *head);
int main(int argc, char *argv[])
{
struct Node *head;
head = (struct Node *)malloc(sizeof(struct Node));
printf("this is mmn 23 Q3, a func that stores a file in a linked list and then prints it.\n");/*
printf("%s\n",argv[1]);
if (argc == 2) { */
head = readFile("tester1.txt");
printList(head);
printListToFile("test.tmp", head);
insertToList(head->next, test);
printf("head");
free(head);
/*}
else if (argc > 2) {
printf("Too many arguments supplied.\n");
} else {
printf("One argument expected.\n");
}*/
return 0;
}
struct Node *makeNode()
{
struct Node *node;
node = (struct Node *)malloc(sizeof(struct Node));
if (node == NULL) {
printf("memory allocation failed\n");
return NULL;
}
node->next = NULL;
return node;
}
/*a method that creates a node with all values, declares a the next node and points it to the next node recieved
and changes the char array to the one recieved.*/
struct Node *makeFullNode(struct Node *Next, char Ptr[])
{
struct Node *node;
node = (struct Node *)malloc(sizeof(struct Node));
node->next = (struct Node *)malloc(sizeof(struct Node));
node->ptr[NICE] = Ptr[NICE];
node->next = Next;
return node;
}
/*the method that reads the file into the list into the char array of each node and returns the head of the list */
struct Node *readFile(char *path)
{
FILE *fptr;
struct Node *curr, *head;
curr = (struct Node *)malloc(sizeof(struct Node));
head = (struct Node *)malloc(sizeof(struct Node));
if (curr == NULL || head == NULL) {
printf("memory allocation failed\n");
return NULL;
}
curr = head;
fptr = fopen(path,"r");
if (fptr == NULL) {
printf("error - failed to open file\n");
exit(0);
return NULL;
}
while (fgets(curr->ptr, NICE, fptr))/*if fgets returns NULL it means that we either reached EOF or error, both a reason to end the loop*/
{
curr->next = makeNode();
curr = curr->next;
}
if(ferror(fptr))/*checking if the loop ended for the right reason*/
{
printf("error - failed to read file\nthis is what we got so far\n");
}
printf("file succesfully read\n");
fclose(fptr);
free(curr);
return head;
}
/*the method that reads the file into the list into the char array of each node and returns the head of the list */
struct Node *readstl(char *path)/*!!!problem!!!*/
{
FILE *fptr;
int i, len;
struct Node *head;
head = (struct Node *)malloc(sizeof(struct Node));
fptr = fopen("readstrtofile.tmp", "w");
if (fptr == NULL) {
printf("error - failed to open file\n");
exit(0);
return NULL;
}
len = strlen(path);
for (i = 0; i < len && fputc(*(path + i), fptr) != EOF; i++);
if (ferror(fptr))/*checking if the loop ended for the right reason*/
{
printf("error - failed to read into file\nthis is what we got so far\n");
}
fclose(fptr);
head = readFile("readstrtofile.tmp");
remove("readstrtofile.tmp");
return head;
}
/*a method that prints the recieved list depending on the list to have the equal length rows.
as specified in mmn 12 tab creating uneven rows is acceptable therefor when ever there is tab in the file
the rows will appear uneven as to tab takes a place of one char but prints to 8 blank spaces in ubuntu */
void printList(struct Node *head)
{
struct Node *curr;
curr = (struct Node *)malloc(sizeof(struct Node));
if (head == NULL) {
printf("empty list\n");
return;
}
if (curr==NULL) {
printf("memory allocation failed\n");
return;
}
printf("this is the list printed nicely\n");
curr = head;
printf("%s\n", curr->ptr);
while (curr->next != NULL) {
curr = curr->next;
printf("%s\n", curr->ptr);
}
printf("\n/********************/\n");
}
/* a method that creates a new file named path and prints a list to it */
void printListToFile(char *path,struct Node *head)/*!!!problem!!!*/
{
struct Node *curr;
char c;
int i;
FILE *fptr;
curr = (struct Node *)malloc(sizeof(struct Node));
if (curr == NULL) {
printf("memory allocation failed\n");
exit(0);
}
curr = head;
fptr = fopen(path, "w+");
if (fptr == NULL) {
printf("error - failed to open file\n");
exit(0);
}
if (head == NULL) {
printf("empty list\n");
exit(0);
}
printf("this is the file %s printed nicely\n",path);
curr = head;
while (curr->next != NULL) {
printf("new node -> ptr -> %s\n",curr->ptr);
/*if(sizeof(curr->ptr)/sizeof(char)<=NICE)
{*/
for(i=0;i<NICE && (c = fputc(curr->ptr[i],fptr)) != EOF;i++);
printf("puting %s to file %s\n",curr->ptr,path);
curr = curr->next;
printf("bolili\n");
/*}
else
{
printf("lilibo\n");
break;
}*/
}
printf("\n/********************/\n");
}
/* a method that recievs a string turns it into a list and inserts it into another list */
void insertToList(struct Node *node, char *str)
{
struct Node *tail, *head;
tail = (struct Node *)malloc(sizeof(struct Node));
head = (struct Node *)malloc(sizeof(struct Node));
if (tail == NULL || head == NULL) {
printf("memory allocation failed\n");
return;
}
head = readstl(str);/*reading the string to a node*/
printList(head);
printf("\n/***********in insert*********/\n");
tail = head;
while (tail->next) {
tail = tail->next;
}/*getting tto the last node to connect it*/
strcpy(tail->ptr, node->next->ptr);/*connecting the lists*/
tail->next = node->next->next;
strcpy(node->ptr, head->ptr);
node->next = head->next;
printf("inserted string successfully\n");
}
/* a method that returns the size of the list*/
unsigned int sizeOfList(struct Node *head)
{
struct Node *tmp;
int size;
if (!(head))
return 0;
size = 1;
tmp = (struct Node *)malloc(sizeof(struct Node));
tmp = head;
while ((tmp = tmp->next))
size++;
return size;
}
header file
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define NICE 80
#define debug "\n/****************/\n"
/*the node structure of a the list which contains a string the size we choose is nice
to print by and a pointer to the next node in the list. */
struct Node {
char ptr[NICE];
struct Node *next;
};
/*makeNode - a method that returns a newely created node and sets all values to NULL values.*/
struct Node *makeNode();
/*makeFullNode - a method that return a newely created node with values set to params as listed below.
#param Next - tho ptr to the next node desired.
#param Ptr - the string that will go into the node ptr.*/
struct Node *makeFullNode(struct Node *Next, char *Ptr);
/*readFile - a method that reads a file into a linked list returning the head to that list.
it reads the file using fgets and a const to decide what size the node strings should be.
#param path - the name of the file to open.
#return the head of the list.*/
struct Node *readFile(char *path);
/*readstl - a method that reads a string into a linked list returning the head to that list.
it prints the list to a tmp file then reads the file using readFile.
#param path - the string to read.
#return the head of the list.*/
struct Node *readstl(char*);
/*printList - a method that prints the list to stdout.
it goes in loop on the nodes each time printing the node->ptr.
#param head - the head of the linked list.*/
void printList(struct Node *head);
/*insertToList - a method that inserts a string into list.
it creates a new list using readstl the connects the nodes using the basic method.
#param node - the node to override.
#param str - the string to insert.*/
void insertToList(struct Node *node, char *str);
/*a method that prints the list to stdout.
it goes in loop on the nodes each time printing the node->ptr.
#param head - the head of the linked list.*/
void printListToFile(char *path,struct Node *head);
/*sizeOfList - a method that returns how many node are in the list.
it goes in a while loop incresing counter by 1 each iteration.
#param head - the head of the list to measure.
#return the size of the list.*/
unsigned int sizeOfList(struct Node *head);
I think it is this line:
for(i=0;i<NICE && (c = fputc(curr->ptr[i],fptr)) != EOF;i++);
Why would fputc ever return EOF if everything goes right? It will try to write characters behind the ptr array. From the manpage of fputc:
fputc(), putc() and putchar() return the character written as an unsigned char cast to an int or EOF on error.
This means, your loop writes as long as fputc doesn't return an error code. But what you probably want, is writing either 80 (NICE is not a nice constant name) or strlen(curr->ptr) characters. Assuming based on your readFile function, you want both things as a limit. I would recommend rewriting this line as:
int len = strnlen(curr->ptr, 80);
if (fwrite(curr->ptr, 1, len, fptr) < 0) {
printf("error writing file");
}
or if the string is always null terminated:
if (fputs(curr->ptr, fptr) < 0) {
printf("error writing file");
}
Also ptr is not a good name for an array. It might confuse people or even you after some time, trying to understand the code. A better name would be value or text (even arr would be better, because it is not a pointer).
In readFile you have a loop in which you read a line and put it in curr->ptr and then create a new curr and link it to the previous curr.
This creates an extra empty curr at the end of the list which you don't need and so you free it later. Unfortunately, the next pointer of the previous node is still pointing at the empty node you just freed.
The easiest way to fix this without restructuring the loop a bit is to keep a record of the previous node, something like this:
struct Node* prev = NULL;
while (fgets(curr->ptr, NICE, fptr))/*if fgets returns NULL it means that we either reached EOF or error, both a reason to end the loop*/
{
curr->next = makeNode();
prev = curr;
curr = curr->next;
}
free(curr);
if (prev != NULL)
{
prev->next = NULL;
}
else
{
head = NULL; // For the empty file case. head == curr in this case
}
// The other clean up stuff

Cannot sort a linked list of dynamically assigned nodes

My program takes in any number of words from the user, and stops only when the user types three asterisks (***). These words will be stored in a linked list and sorted, but the elements in the list are not sorted when I try to print the list. Why is this happening?
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define MAX_STRING_LEN 32 // Limit on length of each string
/* Link list node */
struct Node
{
int data;
struct Node* next;
};
// Function to insert a given node in a sorted linked list
void sortedInsert(struct Node**, struct Node*);
// function to sort a singly linked list using insertion sort
void insertionSort(struct Node **head_ref)
{
// Initialize sorted linked list
struct Node *sorted = NULL;
// Traverse the given linked list and insert every
// node to sorted
struct Node *current = *head_ref;
while (current != NULL)
{
// Store next for next iteration
struct Node *next = current->next;
// insert current in sorted linked list
sortedInsert(&sorted, current);
// Update current
current = next;
}
// Update head_ref to point to sorted linked list
*head_ref = sorted;
}
/* function to insert a new_node in a list. Note that this
function expects a pointer to head_ref as this can modify the
head of the input linked list (similar to push())*/
void sortedInsert(struct Node** head_ref, struct Node* new_node)
{
struct Node* current;
/* Special case for the head end */
if (*head_ref == NULL || (*head_ref)->data >= new_node->data)
{
new_node->next = *head_ref;
*head_ref = new_node;
}
else
{
/* Locate the node before the point of insertion */
current = *head_ref;
while (current->next!=NULL &&
current->next->data < new_node->data)
{
current = current->next;
}
new_node->next = current->next;
current->next = new_node;
}
}
/* BELOW FUNCTIONS ARE JUST UTILITY TO TEST sortedInsert */
/* Function to print linked list */
void printList(struct Node *head)
{
struct Node *temp = head;
while(temp != NULL)
{
printf("%s \n ", temp->data);
temp = temp->next;
}
}
/* A utility function to insert a node at the beginning of linked list */
void push(struct Node** head_ref, int new_data)
{
/* allocate node */
struct Node* new_node = (struct Node*)malloc(sizeof(struct Node));
/* put in the data */
new_node->data = new_data;
/* link the old list off the new node */
new_node->next = (*head_ref);
/* move the head to point to the new node */
(*head_ref) = new_node;
}
// Main function
int main()
{
struct Node *a = NULL;
int index=1;
int i;
char * strings[MAX_STRINGS]; // Array of pointers
do
{
strings[index] = malloc(MAX_STRING_LEN * sizeof(char));
printf("Please input a word : ", index);
fgets(strings[index],MAX_STRING_LEN,stdin);
strtok(strings[index], "\n")=='\0';
}
while(strcmp(strings[index++], "***")!=0);
printf("\nThe input set, in alphabetical order:\n");
for (i = 1; i < index-1; i++)
{
push(&a, strings[i]);
}
insertionSort(&a);
printList(a);
free(strings[i]);
return 0;
}
Input:
pear
apple
***
Given output:
pear
apple
Expected output:
apple
pear
Hii I spent some time thinking what you wanted to do. And saw many problems with your code. I think you want something like this.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define MAX_STRING_LEN 32 // Limit on length of each string
#define MAX_STRINGS 100 // Limit the number of strings
struct Node {
char *data;
struct Node *next;
};
void sortedInsert(struct Node **head_ref, struct Node* new_node) {
struct Node *counter = *head_ref;
struct Node *previous = NULL;
while (counter != NULL && strcmp(counter->data,new_node->data) < 0){
previous = counter;
counter = counter->next;
}
if (previous != NULL) {
previous->next = new_node;
new_node->next = counter;
} else {
new_node->next = *head_ref;
*head_ref = new_node;
}
}
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 = NULL;
if (!head_ref) {
*head_ref = new_node;
return;
}
sortedInsert(head_ref,new_node);
}
void printList(struct Node *head) {
struct Node *temp = head;
while(temp != NULL) {
printf("%s\n", temp->data);
temp = temp->next;
}
}
void freeLinkedList(struct Node *head) {
struct Node *next;
while(head) {
next = head;
head = head->next;
free(next);
}
}
// Main function
int main() {
struct Node *a = NULL;
int index = 0;
int i;
char * strings[MAX_STRINGS]; // Array of pointers
do {
strings[index] = malloc(MAX_STRING_LEN * sizeof(char));
printf("Please input a word %d: ", index);
scanf("%s",strings[index]);
fflush(stdin);
} while(strcmp(strings[index++], "***") != 0 && index < MAX_STRINGS);
printf("\nThe input set, in alphabetical order:\n");
for (i = 0; i < index-1; i++) push(&a, strings[i]);
printList(a);
return 0;
}
I have tested it and it works fine.
If you have any doubts I would like to clear them.
If you want to know what's buggy in your code please feel free to ask.

Create a new node for each entry in a .txt file

Okay so I've been doing a program which would read elements of a txt file using scanf (cmd input redirection). A new node must be created for every entry in the file and add it at the end of the list. Here's my code so far:
struct Elem{
int Atnum;
char Na[31];
char Sym[4];
};
struct nodeTag {
struct Elem entry;
struct nodeTag *pNext; // pointer to the next node
};
typedef struct nodeTag Node;
The function that would initialize it is this:
Node *
InitializeList(Node *pFirst, int n)
{
int i;
Node *head, *temp = 0;
pFirst = 0;
for (i=0; i<n; i++){
head = (Node *)malloc(sizeof(Node));
scanf("%d", &head->entry.AtNum);
scanf("%s", head->entry.Na);
scanf("%s", head->entry.Sym);
if (pFirst != 0)
{
temp->pNext = head;
temp = head;
}
else
{
pFirst = temp = head;
}
fflush(stdin);
temp->pNext = 0;
}
return pFirst;
}
and lastly, print it
void
Print( Node *pFirst )
{
Node *temp;
temp = pFirst;
printf("\n status of the linked list is\n");
while (temp != 0)
{
printf("%d %s %s", temp->entry.AtNum, temp->entry.Na, temp->entry.Sym);
temp = temp -> pNext;
}
}
Now, I can't get the program to run properly. No run-time errors though but the output seems to be garbage. I've been working for hours for this and I cant' get my head around it. Thank you for your help!
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct Elem
{
int AtNum;
char Na[31];
char Sym[4];
};
struct nodeTag
{
/* entry must be a pointer in order to not lose the values
and/or encounter memory conflicting errors
*/
struct Elem *entry;
struct nodeTag *pNext;
};
typedef struct nodeTag Node;
// insert node at the first location
Node *insertFirst(Node *head, struct Elem *data)
{
Node *node = (Node *) malloc(sizeof(Node));
// fill in data
node->entry = data;
/* point it to old first node
in simple words: "put this node before the head"
*/
node->pNext = head;
// point first to new first node
head = node;
return head;
}
Node *InitializeList(int n)
{
int i;
Node *head = NULL;
struct Elem *data;
for (i = 0; i < n; i++)
{
// allocate memory for the struct Elem of each node
data = (struct Elem*) malloc(sizeof(struct Elem));
scanf("%d", &data->AtNum);
scanf("%s", data->Na);
scanf("%s", data->Sym);
head = insertFirst(head, data);
}
return head;
}
//display the list
void printList(Node *head)
{
Node *ptr = head;
printf("\nStatus of the linked list is:\n");
//start from the beginning
while(ptr != NULL)
{
printf("%d %s %s", ptr->entry->AtNum, ptr->entry->Na, ptr->entry->Sym);
printf("\n");
ptr = ptr->pNext;
}
}
int main(int argc, char *argv[])
{
Node *head;
head = InitializeList(3);
printList(head);
return 0;
}
I hope I didn't come too late! If not, please check this answer as the solution, thanks! :-)

Having trouble inserting a node before another node in a linked list?

I'm attempting to alphabetize a linked list as I insert into it (from a file) - I currently have three checks (I'll be using this to explain my logic - if someone has a better idea, please let me know, I've been pulling my hair out over this for the entire day):
If the word grabbed from the file matches the word in the current node, simply increment the frequency counter in the node (don't bother creating a new node). If the word comes before the current node, point previous->next to the newly created node, and point new_node->next to current node. If the word comes after the current node, point the new node to current_node->next, then set current_node->next to the new_node.
My problem is that when I try to run this program and use a file where the second word in the file comes BEFORE the first word, and try to print the linked list, I get locked in an infinite loop - I've narrowed down the issue to the fact that somewhere, a node pointer isn't getting updated, but I don't know where, and I'm at my wit's end.
I'll attach the two files that I have, if anyone could help me, I'd really appreciate it. (There are a few debugging lines in there that aren't really necessary, I was using them to attempt to figure out where the problem was.)
most_freq.h
#ifndef MOST_FREQ_H_
#define MOST_FREQ_H_
#include <stdio.h>
//used to hold each "word" in the list
typedef struct word_node
{
char *word;
unsigned int freq; //frequency of word
struct word_node *next;
} word_node;
struct node *readStringList(FILE *infile);
int readLine(FILE *infile, char * line_buffer);
struct node *getMostFrequent(struct word_node *head, unsigned int num_to_select);
void printStringList(struct word_node *head);
void freeStringList(struct word_node *head);
#endif
most_freq.c
#include "most_freq.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/* TODO
0. Check if item is in list (make all strings lowercase)
1a. if not, insert into list
1b. if it is, increment counter for struct */
struct word_node *head = NULL; //unchanging head node
char* str_buffer = NULL;
struct node *readStringList(FILE *infile) {
char * line = NULL;
size_t len = 0;
ssize_t read;
char* tmp_buffer = (char*) malloc(sizeof(char) * 255);
while(readLine(infile, tmp_buffer) == 1) {
if(head == NULL) { //if the linked list is empty
//allocate space for node
head = (word_node*) malloc (sizeof(word_node));
//set as head node
str_buffer[ strlen(str_buffer) - 1 ] = '\0';
head->word = str_buffer; //set string of node to str_buffer
head->freq = 1; //set frequency to 0
head->next = NULL; //since we're at the first item of the list there is no next
}
else { //else, there is already a node in the list
printf("Linked list has a node.\n\n");
struct word_node *curr = head; //set curr to head (for traversal)
struct word_node *prev = head; //to keep track of the last node
while(curr != NULL) { //while current is not null, continue traversal
/* If string buffer matches current node's word, then simply update the frequency count */
if(strcmp(str_buffer,curr->word) == 0) { //if word matches the word in the list
curr->freq++; //update the current node's frequency
break;
}
/* If string buffer comes after current word (in alphabet) then point temp node->next to current->next, and point current node->next to temp */
else if(strcmp(str_buffer,curr->word) > 1) {
printf("Word comes after current node.\n");
word_node* temp = (word_node*) malloc (sizeof(word_node)); //allocate node for current str_buffer
temp->word = str_buffer;
temp->next = curr->next; //set temp node->next to current node's next
curr->next = temp; //set current->next to point to newly inserted node
}
else { //otherwise, str_buffer must come before current node
printf("Word comes before current node.\n");
word_node* temp = (word_node*) malloc (sizeof(word_node)); //allocate node for current str_buffer
temp->word = str_buffer;
printf("Previous Node: %s\n", prev->word);
printf("Current Node: %s\n", curr->word);
prev->next = temp;
temp->next = curr;
}
prev = curr;
curr = curr->next; //move current node up by one
}
}
}
printStringList(head);
exit(EXIT_SUCCESS);
}
int readLine(FILE *infile, char * line_buffer) {
char * line = NULL;
size_t len = 0;
ssize_t read;
while ((read = getline(&line, &len, infile)) != -1) {
line_buffer = line;
str_buffer = (char*) malloc (sizeof(line));
strncpy(str_buffer, line_buffer, strlen(line));
if(str_buffer[0] != '\0') {
return 1;
}
else
return -1;
}
}
void printStringList(struct word_node *top) {
struct word_node *curr = top; //set curr to head (for traversal)
printf("List of Strings (and Frequencies)\n\n");
int count = 0;
while(curr != NULL) {
printf("%s (Frequency: %d)\n", curr->word, curr->freq);
curr = curr->next;
count++;
}
return;
}
int main(int argc, char *argv[])
{
FILE *file = fopen( argv[1], "r" );
/* fopen returns 0, the NULL pointer, on failure */
if ( file == 0 )
{
printf( "Could not open file.\n" );
}
else
{
readStringList(file);
}
}
test text file (passed in as a parameter when running from terminal)
foofoo
dog
else { //otherwise, str_buffer must come before current node
....
prev->next = temp;
temp->next = curr;
If the list has only one node then curr and prev point to the same node and you are introducing a loop here.Initially you are setting both prev and curr as head.You should set prev as NULL initially and then handle the case if the new node is going to become the first node(when prev will be NULL)
str_buffer[ strlen(str_buffer) - 1 ] = '\0';
head->word = str_buffer; //set string of node to str_buffer
Also you are allocating memory for temp_buffer and using str_buffer which is just a pointer.You might want to use temp_buffer here.
In this part:
else { //otherwise, str_buffer must come before current node
printf("Word comes before current node.\n");
word_node* temp = (word_node*) malloc (sizeof(word_node)); //allocate node for current str_buffer
temp->word = str_buffer;
printf("Previous Node: %s\n", prev->word);
printf("Current Node: %s\n", curr->word);
prev->next = temp;
temp->next = curr;
}
you need to add a check for curr == head (or curr == prev). That case will require special treatment as you need to update head.
Otherwise you get an endless loop. In that case your current code actually do:
head->next = newnode;
newnode->next = head;
which makes the list circular (and an endless loop while printing).
You need something like:
if (curr == head)
{
temp->next = head;
head = temp;
....
}
else
{
....
}
Apart from the fact that you need to handle adding to the front as a special case to update your head pointer, I find the memory allocation in your readLine routine confusing:
char* str_buffer = NULL; // 1
struct node *readStringList(FILE *infile) {
[...]
char* tmp_buffer = (char*) malloc(sizeof(char) * 255); // 2
while(readLine(infile, tmp_buffer) == 1) { // 3
int readLine(FILE *infile, char * line_buffer) {
char * line = NULL;
while ((read = getline(&line, &len, infile)) != -1) { // 4
line_buffer = line; // 5
str_buffer = (char*) malloc (sizeof(line)); // 6
strncpy(str_buffer, line_buffer, strlen(line)); // 7
You're doing three (3) memory allocations for each line read here, there's one done by getline at [4], since you passed in a NULL, another in readLine at [6], and a third one in readStringList at [2]. The tmp_buffer ([2]) isn't used anywhere in readStringList and neither does readLine use the respective argument (the pointer is just overwritten at [5]).
Also, there's no need to use a global variable here [1], your functions should use their arguments to pass the data (and have those arguments already).
Since you use getline, you can just return the buffer allocated by it to the outer function, and use it there directly.
Something like this:
int readLine(FILE *infile, char **line_buffer) {
char * line = NULL;
size_t len = 0;
ssize_t read;
while ((read = getline(&line, &len, infile)) != -1) {
*line_buffer = line;
if(read == 0 || read == -1)
return -1;
return 1;
}
}
struct node *readStringList(FILE *infile) {
char* str_buffer;
while(readLine(infile, &str_buffer) == 1) {
// do something with str_buffer
// though remember to save it somewhere, you need to free() it later
}
[...]

Resources