The program specifications are pretty simple, just read in an input file of words and create a linked list where each node contains an entire string.
Here's my node struct:
typedef struct wordNode{
char *word;
token_type type;
struct wordNode *next;
} wordNode;
The token type will come into play later after I get the LL basics working.
The general process of main is to open the input file, set up head with the first word, then iterate through the rest of the input file using a second node pointer, "current". Afterwards, print the list from the head pointer with a print list function.
void printList(wordNode *head)
{
while(head != NULL)
{
printf("%s ", head->word);
head = head->next;
}
}
int main()
{
//Open input file
FILE *input = fopen("input.txt", "r");
char nextWord[12] = "";
//Scan in first word for head node
fscanf(input, "%s", nextWord);
//create head, fill it in with the first word, and create current
wordNode *head = malloc(sizeof(wordNode));
head->next = malloc(sizeof(wordNode));
head->word = nextWord;
printf("%s ", head->word);
wordNode *current = head->next;
//Begin Iteration
while(fscanf(input, "%s", nextWord) != EOF)
{
current = (wordNode*)malloc(sizeof(wordNode));
current->word = nextWord;
current->next = NULL;
printf("%s ", current->word);
current = current->next;
}
printList(head);
}
Together, those printfs within main will give me the output I want, so the strings seem to be being saved properly during the iteration, But the output given by the printList function is the last word in the list repeated a couple times followed by garbage values.
I'm thinking head is tied to current in some way and doesn't stay put at the beginning of the list through the iteration, but I'm not sure how or why its moving.
Also, should I use strcpy for saving the strings to the nodes? I tried earlier but it was leading to crashes when I tried.
nextWord should either be a much larger array (e.g. nextWord[200]) or you should limit the number of characters stored by fscanf, e.g.
fscanf(input, "%11s", nextWord);
Or use a larger array and limit the number of characters.
You need to make a copy of each string after reading it into the nextWord array. The code currently just assigns the address of the nextWord array to each word pointer. So every node in the linked list points to the same string, which will be the last string read from the file. To copy a string, you need to allocate memory and then strcpy. The strdup function will do that for you, but strdup is not supported on all systems.
When the code creates the head it allocates memory for two structures. Instead, it should allocate memory for one structure and set head->next to NULL.
The variable current is a mess, e.g. you set current->next = NULL and two lines later set current = current->next. To make the code work, you need two variables, I would call them tail and current. tail should point to the last node in the linked list. So initially, tail points to head. When you create a new node, the code should look like this
current = (wordNode*)malloc(sizeof(wordNode));
current->word = strdup( nextWord );
current->next = NULL;
tail->next = current;
tail = current;
Also, don't check fscanf for EOF. Instead, check that fscanf returns the expected number of conversions. The reason is that fscanf could get stuck in an infinite loop if a conversion fails before the end-of-file is reached. So the while loop should be
while(fscanf(input, "%11s", nextWord) == 1)
You need to allocate memory for the char *s:
int main()
{
//Open input file
FILE *input = fopen("input.txt", "r");
char nextWord[12] = "";
//Scan in first word for head node
fscanf(input, "%s", nextWord);
//create head, fill it in with the first word, and create current
wordNode *head = malloc(sizeof(wordNode));
head->next = malloc(sizeof(wordNode));
head->word = (char *)calloc(strlen(nextWord) + 1);
strcpy(head->word, nextWord);
printf("%s ", head->word);
wordNode *current = head->next;
//Begin Iteration
while(fscanf(input, "%s", nextWord) != EOF)
{
current = (wordNode*)malloc(sizeof(wordNode));
current->word = (char *)calloc(strlen(nextWord) + 1);
strcpy(current->word, nextWord);
current->next = NULL;
printf("%s ", current->word);
current = current->next;
}
printList(head);
}
Because you are not saving the input. Only their addresses saving in the linked list.
When you assinged head->word = nextWord the address of the nextWord which is a local aray is assigning.
You need to enough space in the struct like char Word[SIZE] or use dynamic allocation char *Word = malloc( SIZE ) and you should use strcpy to copy the input.
head->word = malloc(SIZE);
strcpy(heap->word, nextWord);
Also there is a little mistake
wordNode *head = malloc(sizeof(wordNode));
head->next = malloc(sizeof(wordNode)); /* (1) Allocated */
head->word = nextWord;
printf("%s ", head->word);
wordNode *current = head->next; /* current points allocated memory (1) */
//Begin Iteration
while(fscanf(input, "%s", nextWord) != EOF)
{
current = (wordNode*)malloc(sizeof(wordNode)); /*re-allocation
and (1) is allocated but not used memory you can not access it anymore*/
current->word = nextWord;
current->next = NULL;
printf("%s ", current->word);
current = current->next;
}
printList(head);
}
Related
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().
I'm trying to set up a linked list but just get the same element in every location -
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#define LENGTH 45
typedef struct node
{
char* word;
struct node* next;
}
node;
int main(void)
{
node* head = NULL; //start of list
// open input file
FILE* inptr = fopen("smalllocal", "r");
if (inptr == NULL)
{
printf("Could not open %s.\n", "smalllocal");
return 2;
}
printf("Opened file\n");
//Get a word from dictionary
char str1[LENGTH +1];
while (fscanf(inptr, "%s", str1) != EOF)
{
node* new_node = malloc(sizeof(node)); //malloc space for a new node
if (new_node == NULL)
{
return 3;
}
new_node->word = str1;
// is it the first insertion at this index?
if (head == NULL)
{
new_node->next = head;
head = new_node;
}
else
// collision so insert at front of list
{
new_node->next = head;
head = new_node;
}
}
fclose(inptr);
printf("Closed file\n");
node* pointer = head;
while (pointer != NULL)
{
printf("%s\n", pointer->word);
pointer = pointer->next;
}
return 0;
}
The file 'smalllocal' contains about 15 different words but the print routine at the end just prints out the last element in the file for every location. Can anybody help please??
This isn't the correct way to copy strings in C (you can't assign them using =).
Instead, you need to allocate a character array long enough to hold the string, and use strcpy().
new_node->word = malloc(strlen(str1) + 1);
strcpy(new_node->word, str1);
Don't forget to free() them later to avoid a memory leak.
The reason your program prints the same value over and over is that every node's word pointer points to the str1 array, but that array is reused for each word. So at any given time, no matter how many nodes you have, you only really have one string: inside str1, and naturally its value will be the last string read in your loop.
You are allocating memory for your strcut, but you also need to allocate memory for your string. Change your
new_node->word = str1;
for
new_node->word = malloc(strlen(str1)+1);
strcpy(new_node->word, str1);
so that you allocate the necessary memory to hold the string and then copy it to this allocated memory. Otherwise, all of your nodes word pointer will be pointing to the same string, str1.
Your new_node->word is a pointer, it doesn't contain any characters. All nodes points to the same block of memory. When you insert a new node, you changed the content of str1 so it just prints out the last string.
Use new_node->word = strdup(str1); instead. You need to include string.h header.
You cannot simply do
new_node->word = str1;
You need to allocate memory first and copy the string into memory ...
new_node -> word = (char *) malloc( sizeof(char)*(LENGTH +1) );
strcpy(new_node -> word, str1);
That should do it. Otherwise, all the pointers in the linked list are pointing to the same memory location.
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
}
}
Here, I am trying to read the contents of a file line by line and create a struct for each line. The problem is when I print the list of words, every single one of them is the last word of the file (which is } in this sample). I believe since line changes frequently and I pass a pointer to a char, value of every struct changes as well. I've been trying to fix this problem for nearly a day without any luck. What's a good way to read every word into a struct and link each struct to the linked list?
Note that there are some helper methods used below. I've tested them multiple times and they are working.
Token struct
typedef struct token
{
char* value;
struct token* next;
}TOKEN;
File content
target1:
dependency1
{
command1,
command2
}
Main
TOKEN *head = NULL;
// represents each formatted line from the script file
char* line = malloc(161*sizeof(char));
FILE* fileRead = openFile("RawRules.txt", "r");
while((line = readLine(line, fileRead)) != NULL)
{
head = add(head, line);
}
displaylist(head);
freeNodes(head);
fclose(fileRead);
Add function Modified from http://cprogramminglanguage.net/singly-linked-list-c-source-code.aspx
TOKEN* add(TOKEN *head, char* value){
TOKEN *tmp;
if(head == NULL){
head=(TOKEN *)malloc(sizeof(TOKEN));
if(head == NULL){
printf("Error! memory is not available\n");
exit(0);
}
head-> value = value;
head-> next = head;
}else{
tmp = head;
while (tmp-> next != head)
tmp = tmp-> next;
tmp-> next = (TOKEN *)malloc(sizeof(TOKEN));
if(tmp -> next == NULL)
{
printf("Error! memory is not available\n");
exit(0);
}
tmp = tmp-> next;
tmp-> value = value;
tmp-> next = head;
}
return head;
}
readline function
// reads a line of a file into buffer
char* readLine(char* buffer, FILE* file) {
buffer = fgets(buffer, 161, file);
return buffer;
}
This did not fix the problem either
while(true)
{
char* ll = malloc(161*sizeof(char));
ll = readLine(ll, fileRead);
f(ll != NULL)
head = add(head, ll);
else
break;
}
Sorry, I progammed in C like billion years ago, so call me a noob!
In the add() function, you're simply assigning a char *, rather than allocating any new memory (and then copying) for each string. So each TOKEN ends up pointing at the original buffer. As you're using a single buffer at the top-level, you're overwriting it over and over again.
In short: You need a separate buffer for each line. One way (not necessarily the best way) is to do the following inside add():
int len = strlen(value);
...
tmp->value = malloc(len+1); /* +1 for null terminator */
strncpy(tmp->value, value, len+1);
Remember that at some point, you'll need to free() all of these extra buffers.
I'm trying to create a singly linked list from an input text file for an assignment. I'm trying to do it a little bit at a time so I know my code is not complete. I tried creating the head pointer and just printing out its value and I can't even get that to work, but I'm not sure why. I included the struct, my create list, and print list functions. I didn't include the open file since that part works.
typedef struct List
{
struct List *next; /* pointer to the next list node */
char *str; /* pointer to the string represented */
int count; /* # of occurrences of this string */
} LIST;
LIST *CreateList(FILE *fp)
{
char input[LINE_LEN];
LIST *root; /* contains root of list */
size_t strSize;
LIST *newList; /* used to allocate new list members */
while (fscanf(fp, BUFFMT"s", input) != EOF) {
strSize = strlen(input) + 1;
/* create root node if no current root node */
if (root == NULL) {
if ((newList = (LIST *)malloc(sizeof(LIST))) == NULL) {
printf("Out of memory...");
exit(EXIT_FAILURE);
}
if ((char *)malloc(sizeof(strSize)) == NULL) {
printf("Not enough memory for %s", input);
exit(EXIT_FAILURE);
}
memcpy(newList->str, input, strSize); /*copy string */
newList->count = START_COUNT;
newList->next = NULL;
root = newList;
}
}
return root;
}
/* Prints sinly linked list and returns head pointer */
LIST *PrintList(const LIST *head)
{
int count;
for (count = 1; head != NULL; head = head->next, head++) {
printf("%s %d", head->str, head->count);
}
return head; /* does this actually return the start of head ptr, b/c I want to
return the start of the head ptr. */
}
root has an undefined value, so it won't initialize. The second line of CreateList should be
LIST *root = NULL;
Also, further down there is allocation apparently for the details of the item, but a) the code fails to capture the allocation and save it anywhere, and b) the size of the allocation should be strSize, not the length of the variable itself. There are several ways to fix it, but the most straightforward would be:
newList->str = (char *)malloc(strSize);
if (newList->str == NULL)
The second malloc allocates memory but its return value is not assigned to anything, so that allocated memory is lost.
newList is allocated but not initialized, so using a memcpy to copy memory to newList->str will fail since newList->str points to nothing. Probably you wanted the result of the second malloc to be assigned to newList->str, but you forgot it.
You shouldn't be incrementing head after head = head->next in the for loop. PrintList will return NULL every time since the loop wont stop until head is NULL. Why do you need to return the head of the list you just passed to the function anyway?
Edit:
LIST *current = head;
while (current != NULL) {
printf("%s %d", current->str, current->count);
current = current->next;
}