I'm trying to read line input from a file, correctly parse the line, and add the three fields of information from the line onto a node in a linked list.
Here's my read from file function:
int readFile(char* file)
{
FILE *fp = fopen(file,"r");
char ch;
char line[50];
char string1[100];
char string2[100];
char string3[100];
char endLine[2];
int i = 0;
while(fscanf(fp, "%[^\t]\t%[^\t]\t%[^\n]", string1, string2, string3) == 3)
{
printf( "%s\t%s\t%s\n", string1, string2, string3);
addNode(string1, string2, string3, head, tail);
}
printNodes();
fclose(fp);
return 0;
}
And here is my addNode function:
// create stuff
Entry *entry = malloc(sizeof(Entry));
entry->name = string1;
entry->address = string2;
entry->number = string3;
Node* node = malloc(sizeof(Node));
node->entry = entry;
node->next = NULL;
// Empty list
if(head->next == NULL)
{
head->next = node;
}
// Else, add to the end of the list
else
{
Node* temp = head->next;
while(temp->next!= NULL)
{
temp = temp->next;
}
temp->next = node;
}
I get problems when I call printNodes, and only the last read node's information is printed X times, where X is the number of unique nodes I'm supposed to have. I think I'm having a problem where I'm overwriting an old node each time I create a new node, but I'm not entirely sure, as this is my first time with raw C code.
Thanks again!
EDIT:
here's the printNodes() function:
int printNodes(Node* head)
{
Node *temp = head->next;
while(temp->next != NULL)
{
printf("\n%s\t%s\t%s\n", temp->entry->name, temp->entry->address, temp->entry->number);
temp = temp->next;
}
return 0;
}
Your problem is here:
entry->name = string1;
entry->address = string2;
entry->number = string3;
You are providing the same memory location to every node. Those strings contain the last value you read in when you call printNodes().
Related
I am trying to insert words into a hash table and it looks like it works but when I try to print the word inside the node (just to check if its still correct) I get a bogus value. When my code prompts for the word I said 'Hey' and when it prompts for place I said '5'. The string that is printed out(which is supposed to be the word inside the node) is HH9[]A\A]A^A_f. What is happening to the word inside the node and am I inserting the node correctly?
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
typedef struct node
{
char word[20];
struct node *next;
}
node;
int main (void)
{
node* table[10];
char wrd[10];
printf("Word to insert: ");
fgets(wrd, 10, stdin);
int place;
printf("Place to insert word: ");
scanf("%d", &place);
node *n = malloc(sizeof(node));
if(n == NULL)
{
return 1;
}
strcpy(n->word, wrd);
if(table[place] == NULL)
{
n = table[place];
n->next = NULL;
}
else
{
n->next = table[place];
n = table[place];
}
printf("Word inside node: %s \n" , n->word);
}
EDIT
I changed the code and tried to implement it on a larger scale but my while loop gives me a segfault. This is the function I put it in:
FILE* dct = fopen ("/dictionaries/large", "r");
char *wrd = NULL;
while(fscanf(dct, "%s", wrd) != EOF)
{
int place = hash(wrd);
node *n = malloc(sizeof(node));
node *anchor = NULL;
node *end = NULL;
if(n == NULL)
{
return 1;
}
strcpy(n->word, wrd);
n->next = NULL;
if (!end) //Initial state
anchor = end = n;
else //Every following node.
end = end->next = n;
strcpy(n->word, wrd);
n->next = table[place];
table[place] = n;
counter++;
}
return false;
It has to read from the dictionary file and load the word into memory(or a hash table).
A linked list is a linked list because it does not have a fixed size.
The table array is therefor superfluous.
What you need for your linked list to work is to remember the anchor and nothing more.
A small example:
Node *anchor = NULL;
Node *end = NULL;
Node *node = malloc(sizeof(Node));
node->next = NULL;
if (!end) //Initial state
anchor = end = node;
else //Every following node.
end = end->next = node;
At this point, you can still access the node you've just filled. Don't forget to iterate over your list later and free those allocations though.
This code doesn't make any sense:
if(table[place] == NULL)
{
n = table[place]; // since we know table[place] is null, that sets n to null!
n->next = NULL; // We just set n to NULL, we can't access n->next!
}
else
{
n->next = table[place]; // This sets n to a garbage value since table[place] was never assigned a value
n = table[place]; // This leaks the value we malloc'ed. We were supposed to link it to the list!
}
I am required to have a list of structs of sentence nodes that point to a struct of word nodes. I am trying to print the user's input.
I have a program that runs properly when I manually give it the input (see test section of the code). It does not, however, work when I use my input1() function.
I've tried debugging it, but I can't seem to find the problem.
I removed all printf lines that I used to debug. I also removed all the irrelevant code.
I am looking to know how to fix it and what is wrong so I can run it with no problems.
What I learned from debugging it is that (only when using input1() and not in the test) the head is overwritten every time and all the nodes as well.
I also tried using a double pointer instead of returning para but that didn't help.
any help will be appreciated,
thanks in advance
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h>
typedef struct word
{
char * ch;//poiter to char
}
W;
typedef struct sentence
{
W * currentWord;//pointer to a word
int lineNumber;// holds the line number
int numbersOfWords;//holds the number of words
struct sentence* link;
}
sent;
typedef struct list
{
sent* head;
int count;
}
LISTS;
LISTS* createList()
{
LISTS* list;
list= (LISTS*) malloc (sizeof (LISTS));
if (list)
{
list-> head = NULL;
list-> count = 0;
}
return list;
} // createList
void printList(LISTS* list)
{
sent *temp = list -> head;
//iterate the entire linked list and print the data
while(temp != NULL)
{
printf("%s\n", temp->currentWord->ch);
temp = temp->link;
}
// printf("NULL\n");
}
void insertSentList (LISTS* list, W* itemPtr)
{
sent* newPtr; //new node
if (!(newPtr = (sent * ) malloc(sizeof(sent)))){
printf(" Memory can not be allocated.");
return;
}
newPtr->currentWord = itemPtr;
newPtr->link = NULL;
if(list->head == NULL)
{
list->head = newPtr;
}else{
sent* current = list->head;
while(current->link != NULL){
current = current->link;
}
current -> link = newPtr;
}
(list->count)++;
return;
} // insertList
LISTS * input1(LISTS *para)
{
char * line;
line = (char * ) malloc(1000 * sizeof(char));
line[0] = '\0';
while (line[0] != '\n')
{
W word;
word.ch = (char * ) malloc(100);
printf(" Please input a line : ");
fgets(line, 1000, stdin);
if(line[0] != '\n'){
strcpy(word.ch, line);
insertSentList(para,&word);
}
}
free(line);
return para;
}
int main()
{
///////////////////test////////////////
LISTS* list = createList();
W word;
word.ch= "word0 ";
W word1;
word1.ch= "word1 ";
W word2;
word2.ch= "word2";
insertSentList(list,&word);
insertSentList(list,&word1);
insertSentList(list,&word2);
insertSentList(list,&word);
insertSentList(list,&word1);
insertSentList(list,&word2);
printList(list);
///////////////////test////////////////
LISTS *para = createList();
para= input1(para);
printList(para);
return 0;
}
Main problem with the posted code is that "ownership" of the sent and W objects in a list is not well defined. For example word.ch= "word0 "; in main sets the ch pointer pointing to a string literal (which it does not own), but word.ch = malloc(100); in input1 points it to dynamically allocated memory (which it should own, and remember to free later). Because of this, memory allocations cannot be tracked reliably and, even in the cases where things appear to "work", there are multiple memory leaks. It also breaks when the inserted objects are local variables that do not live for the entire lifetime of the list object.
The simplest (if not necessarily the best or most efficient) solution would be to dynamically allocate all objects that go into the list, make the list own them all, and add a function to cleanup once done. To that end insertSentList could be modified as follows.
void insertSentList (LISTS* list, W* itemPtr)
{
sent* newPtr; //new node
if (!(newPtr = malloc(sizeof(sent)))){
printf(" Memory can not be allocated.\n");
return;
}
W *newItem = malloc(sizeof(W)); // <-- make a deep copy of the `itemPtr` argument
newItem->ch = strdup(itemPtr->ch); // including a copy of the string itself
newPtr->currentWord = newItem; // <-- save the copy in the list, not the argument
newPtr->link = NULL;
if(list->head == NULL)
{
list->head = newPtr;
}else{
sent* current = list->head;
while(current->link != NULL){
current = current->link;
}
current->link = newPtr;
}
list->count++;
} // insertList
For proper cleanup and to avoid memory leaks, the following freeList should be called for each list pointer returned by createList and filled by insertSentList.
void freeList(LISTS *list)
{
sent *temp = list->head;
while(temp != NULL)
{
sent *next = temp->link;
free(temp->currentWord->ch);
free(temp->currentWord);
free(temp);
temp = next;
}
free(list);
}
I have a program that is supposed to take an input file and extract the strings from it and add it to a linked list. I do not think I am adding the strings to the linked list correctly and i cannot seem to find the right way to. When the program executes it goes into an infinite loop for some reason.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct list {
char *string;
struct list *next;
};
typedef struct list LIST;
int main() {
FILE *fp;
char line[128];
char file_name[20];
LIST *current, *head;
char *p, *s;
head = current = NULL;
printf ("Enter the name of the file: ");
scanf("%s",file_name);
fp = fopen(file_name, "r");
while(fgets(line, sizeof(line), fp))
{
p = s = line;
while(*p!=0)
{
if (*p==' ')
{
LIST *node = malloc(sizeof(LIST));
*p = 0;
node->string = strdup(s);
node->next =NULL;
if(head == NULL){
current = head = node;
} else {
current = current->next = node;
}
s = p+1;
}
p++;
}
}
fclose(fp);
//test print
for(current = head; current ; current=current->next){
printf(" %s", current->string);
}
return 0;
}
Several things:
You are using the same node for all words in a line, thereby creating a loop where node->next equals node. You should create a new node when you insert a new word, not when you read a new line.
You don't catch the last word of a line. You can make use of the fact that fgets retains the trailing new-line character and check for that in addition to checking for a space. You could also consider using isspace from <ctype.h>.
Alternatively, and maybe better, is to defer the check for the null terminator until after the loop. You must then add a new word when you read a space or a null character.
You insert empty words when the input file contains consecutive spaces or space characters. Your program should check whether p > s to add only valid words. (Or your program shoul only add valid words when the previously read character wasn't a space.)
You allocate memory for the nodes and the strings. You should free this memory before exiting the program.
Here's your main loop with the fixes described above:
while(fgets(line, sizeof(line), fp))
{
char *p = line;
char *s = line;
do {
if (*p== ' ' || *p == '\n' || *p == '\t' || *p == '\0') {
if (p > s) {
LIST *node = malloc(sizeof(LIST));
*p = 0;
node->string = strdup(s);
node->next = NULL;
if(head == NULL){
head = node;
} else {
current->next = node;
}
current = node;
}
s = p + 1;
}
p++;
}
while (*p != 0);
}
code print elements after store them :
void print(struct node* root)
{
while ( c != NULL )
{
printf( "\n%d ", c->line1);
printf( "%s", c->curr );
c = c->next;
}
}
print method
Just looking at the code, this line seems like a potential issue:
temp->curr=current_input;
It looks like all the nodes .curr will get set = current_input. I'm guessing you need to do something like:
temp->curr = malloc(1 + strlen(current_input));
strcpy(tmp->curr, current_input);
Use strcpy_s if strcpy causes a warning.
First you should realize a list consists of nodes, which contain pieces of your data — so you need to allocate a new node for each piece of data you want to store in a list.
Then you insert each newly created node into the list and finally print the list when done.
Additionaly remember that data need to be either copied into the node (like line1) or copied somewhere else, for example onto the heap, and then linked to the node with a pointer, like curr (see the answer by #rcgldr).
struct node *root = NULL;
struct node *createnode(int line, const char *input)
{
struct node *n = malloc(sizeof(struct node));
if(n != NULL)
{
n->line1 = line;
n->curr = input;
n->next = NULL;
}
return n;
}
void insertnode(struct node* n)
{
n->next = root;
root = n;
}
void printlist(struct node* n)
{
for( ; n != NULL; n = n->next)
{
printf( "%d: %s\n", n->line1, n->curr);
}
}
int main(int argc, const char * argv[])
{
char *input;
struct node *temp;
type t;
do
{
t=getword(); //call to get the type of t
switch (t)
{
case number:
case keyword:
input = strdup(current_input); // make a copy of user input
if(input != NULL)
{
temp = createnode(line, input);
if(temp != NULL) // created?
insertnode(temp); // insert into the list
else
{
free(input); // free unused input copy
t = EOF; // make the loop terminate
}
}
else // user input copy failed
t = EOF; // make the loop terminate
break;
default:
break;
}
}
while (t != EOF);
print(root);
return 0;
}
I need to create a circular doubly linked list with a sentinel node which is supposed to read data from a file and insert it in the list, than perform some operations with it. For now I'm stuck on a simple print function which won't print from a list for some reason. The data in the file is in the form of strings,
example: "Popular Sorting Algorithms,
Bubble Sort, Merge Sort, "empty line", etc
Here is my code so far:
Header file contains:
typedef struct NODE {
struct NODE *prev;
char *value;
struct NODE *next;
} NODE;
typedef struct LIST {
int count;
struct NODE *next;
struct NODE *prev;
} LIST;
int InsertEnd(NODE *head, char * value, int *lineCount);
void printLines(int *lineCount);
void Traverse(NODE *head);
Main contains:
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include "header.h"
int main()
{
int lineCount = 0;
NODE *head;
head = (NODE *)malloc(sizeof(NODE)); /* creates head node dynamically */
head->next = NULL; /* points to first element */
head->prev = NULL; /* points to last element */
head->value = "HEAD"; /* not needed, but it was pretty useful when debugging */
//*********BEGIN OF OPEN FILE FUNCTION
FILE* fp;
char *fname = NULL;
fname = (char *)malloc(200); <<<<<===== I would prefer to set the size dynamically adjusting but I dont know how
printf("Reading file input.txt\n");
//Checks if the file us unable to be opened, then it shows the error message
if ( !(fp = fopen("input.txt", "r")))
{
printf("\nError, Unable to open the file for reading \n");
exit(100);
}
//*********BEGIN OF READ FROM FILE FUNCTION
while (!feof(fp))
{
fgets(fname, 150, fp); //reads the file and stores in buffer
fname[strlen(fname) - 1] = '\0'; // reduces empty strings for input
if (fname != '\0')
{
InsertEnd(head, fname, &lineCount);
//printf("%s\n", head->next->value); <<<<==== If uncomment this print function would work properly but only in this context
}
else
{
printf("Error'\n"); // For debugging
}
}
Traverse(head); // Print Function Should Be Working in Here
printf("Debugging print\n");
printLines(&lineCount); // Shows Line Count
return 0;
}
// Function inserts a new node at the end of the LIST
int InsertEnd(NODE *head, char * value, int* lineCount)
{
int lineCounter = *lineCount;
/* create new node */
NODE *newnode;
newnode = (struct NODE *)malloc(sizeof( struct NODE));
newnode->value = value;
/* placing new node in LIST */
if (head->next == NULL) /* LIST was empty */
{
newnode->next = head;
newnode->prev = head;
head->next = newnode;
head->prev = newnode;
lineCounter++; // Increment line counter
}
else /* LIST wasn't empty */
{
newnode->next = head;
newnode->prev = head->prev;
head->prev->next = newnode; /* adjust node that was previously last */
head->prev = newnode; /* adjust head node */
lineCounter++; // Increment line counter
}
*lineCount = lineCounter;
return lineCount;
}
// This function prints how many lines there are in the LIST, but I need to get rid of the empty spaces
void printLines(int *lineCount)
{
printf("Line counter is %d", *lineCount); // Shows the number of lines, but doesn't skip empty ones.
}
void Traverse(NODE *head)
{
NODE *current = head;
printf("Forward:");
while (current!= head->prev)
{
printf("%s \n", current->value);
current = current->next;
}
printf("\n");
}
Therefore, I have several problems so far:
1) I need to get rid of empty strings in my list most likely. What would be a better approach, to get rid of them while reading or just not displaying when printing? How would I do this exactly?
2) How can I fix my print(traverse) function and whats wrong there?
3) Additionally all of this should be going on through the menu manager which would prompt for a command ( I got this right I think). But there are some functions that I don't know how to implement. For example when used hits "I" it should call Insert functions and prompt the user to enter two more values and , and later insert at the appropriate . How would I do that? Example "I 1 8"
4) Similarly to the previous one, there should be List function which should print lines between specific values. User input format should be "L to " list inclusively. Example "L 2 5"
5) Similarly to previous there should be a delete function with the format "D " inclusively. Example "D 3 7"
6) And the very last is the Save function in the format "S " Example "S output.txt"
Thank You for the help!
I see at least these issues in your code,
In main()
if (fname != '\0')
this should be
if (fname[0] != '\0')
In InsertEnd()
newnode->value = value;
should be
newnode->value = strdup(value);
In you code there should be some correctness which is very help full first as per your request you need to allocate buffer dynamically but not know file length so it can be achived by this one
int sz;
printf("Reading file input.txt\n");
//Checks if the file us unable to be opened, then it shows the error message
if ( !(fp = fopen("sample.txt", "r")))
{
printf("\nError, Unable to open the file for reading \n");
exit(100);
}
fseek(fp, 0L, SEEK_END);
sz = ftell(fp);
printf("size of file %d\n",sz);
fname = (char *)malloc(sz);
rewind(fp);
Now for reading content from file you checked fname to \0 which is not correct i corrected your while..loop.
while (!feof(fp))
{
if(fgets(fname,256, fp) != 0)
{
fname[strlen(fname) - 1] = '\0'; // reduces empty strings for input
InsertEnd(head, fname, &lineCount);
}
else
{
printf("Error'\n"); // For debugging
}
}