Pre-order Fill a tree from file - c

I was wondering if you could help me out I'm really stuck on this code I wrote. I'm supposed to pre-order fill a tree from a file that is structured in the following way.
Hello
goodbye
yes
' ' <- This is an actual space in the file
no
end of file
When ever there is a space I wanna return back to the node previous and go right and return whenever it reaches EOF.
So the text above would be structured in the following way
hello
goodbye null no right child
yes no
This function is supposed to fill my tree in preorder. I'm grabbing the data using my readFile function here
char *readFile(FILE *fp)
{
int c = 0;
int i = 0;
size_t capacity = 10;
char *arr = NULL;
char* temp = NULL;
arr = (char*) malloc(capacity * sizeof(char));
while (((c = fgetc(fp)) != '\n') && (c != EOF))
{
if(capacity == (i+2))
{
capacity *= 2 ;
temp = (char*)realloc(arr,capacity * sizeof(char));
/*Assigns Address to newly allocated array*/
arr = temp;
}
arr[i] = c;
i++;
}
arr[i-1] = '\0';
if(arr[0] == '\r') /* Line spaces to move up*/
{
printf("Got here SPACE\n");
arr[0] = ' ';
}
else if(c == EOF)/*if its an end of file return*/
{
printf("Got here EOF \n");
arr[0] = ' ';
}
return arr;
}
My recursive algorithm to fill the tree is called populate. I'm not really that great at recursion but I've walked though my code multiple times and can't see what's obviously wrong. Currently it seems I can only print the root. Trying to read the left or right root data gives me an immediate seg fault
void populate(FILE *fp,struct node *root)
{
char *data = readFile(fp);
if(data[0] == ' ') /*possible issues with usingn null charater? */ /*statement is true for both EOF and spaces*/
{
return;
}
printf("Creating Node\n");
if(root == NULL)
{
root = createNode();/* create the current root */
root->data = data;/*assign data*/
}
printf("%s\n",data);
populate(fp,root->left);
populate(fp,root->right);
}
my main
int main(int argc, char *argv[])
{
FILE *fp;
node *root = createNode();
fp = fopen("qa.db","r+");
if(fp == NULL)
{
printf("File not open");
}
populate(fp,root);
if(root == NULL){
printf("Equal to NULL\n");
}
printTree(root);
/*check = checkFile(fp)*/
fclose(fp);
return 0;

Related

Problem while opening a file in C on linux

I'm having problems with my C program which works perfectly on Windows but not on Linux. I use the following method for reading line by line a file:
char * getLineOfAnySize(FILE* fp, size_t typicalSize, int *endOfLineDetected,size_t *nrOfCharRead){
char *line; // buffer for our string
int ch; // we will read line character by character
size_t len = 0; // number of characters read (character counter)
size_t lineSize = typicalSize; // initial size of the buffer allocated for the line
*nrOfCharRead = 0;
if(!fp) return NULL; // protection
// allocating the buffer
line = realloc(NULL, sizeof(char)*lineSize); // expected size of the line is pathHead to typicalSize
if (!line) return line; // protection, if we fail to allocate the memory we will return NULL
while (1) { // loop forever
ch = fgetc(fp); // getting character by character from file
if (ch == '\n') break; // end of line detected - breaking the loop
if( ch == EOF) {
*endOfLineDetected = 1;
break; // end of file detected - breaking the loop
}
line[len++] = ch; // store the character in the line buffer, increase character counter
if (len == lineSize){ // we reached the end of line buffer (no more room)
lineSize = lineSize + 64; // we have to increase the line size
line = realloc(line, sizeof(char)*(lineSize)); // line buffer has new size now
if (!line) return line; // if we fail to allocate memory we will return NULL
}
if( (len == 0) && *endOfLineDetected){ // empty file
*endOfLineDetected = 1;
break;
}
}
line[len++] ='\0'; // ending the string (notice there is no '\n' in the string)
*nrOfCharRead = len;
return line; // return the string
}
The workflow of my program is the following: I gave in input a path, the file correspondent to the path contains in each line others file path that I read with the function above and put into a structure. On each i apply the KMP algorithm to get the occurrences of a string.
The problem comes in my program when I try to open the files that correspond to the paths I saved earlier:
FILE *fp = NULL;
fp = fopen(list->path, "r");
if(fp == NULL){
fprintf(stderr, "Cannot open %s, exiting. . .\n", list->path);
exit(1);
}
On the screen is displayed:
, exiting ...
This is so weird because of file opening problem the output should be:
Cannot open "list->path content", exiting. . .
Even though I don't know why it gives me this error while opening the path read from the input file. During compiling there's no problem. I was thinking about buffer problems derived by the function "getLineOfAnySize. I'm not a Linux user, I was just trying to run the program in order to make sure it will run on both OS. Don't think about design issues or logical issues because on Windows everything works perfectly. Big up to everyone who will help me! Please ask further information about the code if needed.
EDIT:
The content of the input file is:
/home/xxx/Scrivania/find/try
/home/xxx/Scrivania/find/try1
Note that find is the directory of the project.
The following is a sample of my program in order to make more sense of variable and construct:
foo.c :
#include "foo.h"
FILE *fInput = NULL;
FILE *fp = NULL;
char *line1;
char *line2;
int endOfLineDetected = 0;
size_t nrOfCharRead = 0;
char ch;
fWord *w = NULL;
fWord *wordHead = NULL;
fWord *wordTail = NULL;
fList *list = NULL;
fList *listHead = NULL;
fList *listTail = NULL;
fPath *pathHead = NULL;
fPath *pathTail = NULL;
fPosition *positionHead = NULL;
fPosition *head = NULL;
fPosition *current = NULL;
char * getLineOfAnySize(FILE* fp, size_t typicalSize, int *endOfLineDetected,size_t *nrOfCharRead);
int main(int argc, char *argv[]){
fInput = fopen(argv[1], "r"); //the file that contains the path of the file in which search.
if(fInput == NULL){
fprintf(stderr, "Cannot open %s, exiting. . .\n", argv[1]);
exit(1);
}
while(!endOfLineDetected){ //read line by line the input file in order to save the path in a structure
line1 = getLineOfAnySize(fInput,128,&endOfLineDetected,&nrOfCharRead);
fList *node = malloc (sizeof(fList));
node->path = line1;
node->next = NULL;
if(listHead == NULL){
listHead = listTail = node;
}else{
listTail = listTail->next = node;
}
}
list = listHead;
fclose(fInput);
do{
fWord *app = malloc(sizeof(fWord));
printf("Insert the word to search: ");
scanf("%s", app->word);
app->totalOccurences = 0;
app->p = NULL;
app->next = NULL;
if(wordHead == NULL){
wordTail = wordHead = app;
}else{
wordTail = wordTail->next = app;
}
printf("Do you want to insert another word? (Y/N): ");
scanf(" %c", &ch);
}while(ch == 'y' || ch == 'Y');
w = wordHead;
while(w != NULL){
while(list != NULL){
w->p = malloc(sizeof(fPath));
w->p->fileOccurrences = 0;
w->p->path = list->path;
w->p->position = NULL;
w->p->next = NULL;
if(pathHead == NULL){
pathTail = pathHead = w->p;
}else{
pathTail = pathTail->next = w->p;
}
fp = fopen(w->p->path, "r");
if(fp == NULL){
fprintf(stderr, "Cannot open %s, exiting. . .\n", w->p->path);
exit(1);
}
int countLine = 0;
endOfLineDetected = 0;
while(!endOfLineDetected){
line2 = getLineOfAnySize(fp,128,&endOfLineDetected,&nrOfCharRead);
int n = strlen(line2);
int m = strlen(w->word);
w->p->fileOccurrences = w->p->fileOccurrences + KMP(line2, w->word, n, m, countLine, w->p);
countLine = countLine + 1;
}
w->totalOccurences = w->totalOccurences + w->p->fileOccurrences;
w->p->position = getHead();
w->p = w->p->next;
list = list->next;
fclose(fp);
}
w->p = pathHead;
list = listHead;
w = w->next;
pathHead = NULL;
}
w = wordHead;
while(w != NULL){
printf("WORD %s \r\n", w->word);
printf("TOTAL %d \r\n", w->totalOccurences);
pathHead = w->p;
while(w->p != NULL){
printf("FILE %s \r\n", w->p->path);
printf("OCCURENCES %d \r\n", w->p->fileOccurrences);
positionHead = w->p->position;
while (w->p->position != NULL){
printf("%d %d\r\n", w->p->position->line, w->p->position->character);
w->p->position = w->p->position->next;
}
w->p->position = positionHead;
w->p = w->p->next;
}
w->p = pathHead;
w = w->next;
}
w = wordHead;
printf("\r\n");
freeMemory();
freeKMP();
return 0;
}
char * getLineOfAnySize(FILE* fp, size_t typicalSize, int
*endOfLineDetected,size_t *nrOfCharRead){
char *line; // buffer for our string
int ch; // we will read line character by character
size_t len = 0; // number of characters read (character counter)
size_t lineSize = typicalSize; // initial size of the buffer allocated for the line
*nrOfCharRead = 0;
if(!fp) return NULL; // protection
// allocating the buffer
line = realloc(NULL, sizeof(char)*lineSize); // expected size of the line is pathHead to typicalSize
if (!line) return line; // protection, if we fail to allocate the memory we will return NULL
while (1) { // loop forever
ch = fgetc(fp); // getting character by character from file
if (ch == '\n') break; // end of line detected - breaking the loop
if( ch == EOF) {
*endOfLineDetected = 1;
break; // end of file detected - breaking the loop
}
line[len++] = ch; // store the character in the line buffer, increase character counter
if (len == lineSize){ // we reached the end of line buffer (no more room)
lineSize = lineSize + 64; // we have to increase the line size
line = realloc(line, sizeof(char)*(lineSize)); // line buffer has new size now
if (!line) return line; // if we fail to allocate memory we will return NULL
}
if( (len == 0) && *endOfLineDetected){ // empty file
*endOfLineDetected = 1;
break;
}
}
line[len++] ='\0'; // ending the string (notice there is no '\n' in the string)
*nrOfCharRead = len;
return line; // return the string
}
// Function to implement KMP algorithm
int KMP(const char* X, const char* Y, int m, int n, int line, fPath *app){
int count = 0;
// next[i] stores the index of next best partial match
int next[n + 1];
for (int i = 0; i < n + 1; i++)
next[i] = 0;
for (int i = 1; i < n; i++){
int j = next[i + 1];
while (j > 0 && Y[j] != Y[i])
j = next[j];
if (j > 0 || Y[j] == Y[i])
next[i + 1] = j + 1;
}
for (int i = 0, j = 0; i < m; i++){
if(X[i] == Y[j]){
if (++j == n){
count = count + 1; //conta le occorrenze della parola nella riga in input
fPosition *node = malloc (sizeof(fPosition));
node->line = line;
node->character = i - j + 1;
node->next = NULL;
if(head == NULL){
current = head = node;
}else{
current = current->next = node;
}
app->position = current;
}
}
else if (j > 0) {
j = next[j];
i--; // since i will be incremented in next iteration
}
}
return count;
}
fPosition * getHead(){ //rimette il puntatore alla testa della lista
fPosition *app = head;
head = NULL;
return app;
}
void freeKMP(){
free(head);
free(current);
}
void freeMemory(){
list = listHead;
fList *tempL = NULL;
while(list != NULL){
tempL = list;
list = list->next;
free(tempL);
}
w = wordHead;
fWord *tempW = NULL;
fPath *tempP = NULL;
fPosition *tempO = NULL;
while(w != NULL){
while(w->p != NULL){
while(w->p->position != NULL){
tempO = w->p->position;
w->p->position = w->p->position->next;
free(tempO);
}
tempP = w->p;
w->p = w->p->next;
free(tempP);
}
tempW = w;
w = w->next;
free(tempW);
}
free(w);
free(line1);
free(line2);
free(wordHead);
free(wordTail);
free(listHead);
free(listTail);
free(pathHead);
free(pathTail);
free(positionHead);
}
foo.h:
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
struct fileList{
char *path;
struct fileList *next;
};
struct filePath{
char *path;
int fileOccurrences;
struct OccurrencesPosition *position;
struct filePath *next;
};
struct fileWord{
char word[50];
int totalOccurences;
struct filePath *p;
struct fileWord *next;
};
struct OccurrencesPosition{
int line;
int character;
struct OccurrencesPosition *next;
};
typedef struct filePath fPath;
typedef struct fileWord fWord;
typedef struct OccurrencesPosition fPosition;
typedef struct fileList fList;
fPosition * getHead();
int KMP(const char* X, const char* Y, int m, int n, int line, fPath *app);
void freeMemory();
void freeKMP();
Maybe also the way I free memory isn't correct.
This is not a full answer, but a hint for further analysis.
I tested the program with the input file contents as shown in the question and entered one or two words.
If the first file does not exist, I get an error message as expected:
Cannot open /home/yuripaoloni/Scrivania/find/try, exiting. . .
Then I modified the input file to list two files that exist on my system and get an error message
Cannot open , exiting. . .
I extended the code that tries to open the file to get more output:
fp = fopen(w->p->path, "r");
if(fp == NULL){
fprintf(stderr, "Cannot open %s, exiting. . .\n", w->p->path);
perror("fopen");
exit(1);
} else {
printf("Successfully opened %s\n", w->p->path);
}
This prints
$ ./foo input
Insert the word to search: foo
Do you want to insert another word? (Y/N): y
Insert the word to search: bar
Do you want to insert another word? (Y/N): y
Insert the word to search: baz
Do you want to insert another word? (Y/N): n
Successfully opened /home/username/tmp/try
Successfully opened /home/username/tmp/try1
Cannot open , exiting. . .
fopen: No such file or directory
Apparently your program tries to open a third file after the existing file names. w->p->path might be a NULL pointer or may point to an empty string.
The same error occurs when I enter only one word. I did not further analyze the error.
To find out why your program tries to open a file with an empty name, you can run it in a debugger or add more output to see how many loop cycles are executed when processing the lists and which data you find.

Readdir() results added to linked list causes seg fault

So I'm looping through readdir() function calls and adding the resulting file name to a new node in a linked list. After fixing an issue by setting file_list = add_file_node(), I'm running into and issue where the dir_list loop is having problems accessing the directory.
hls: cannot access hls: cannot access h: No such file or directory
code:
#include "header.h"
/**
* main - main ls function
*
* #argc: argument count
* #argv: argument vector
*
* Return: 0, or the errno of the error
*/
int main(int argc, char **argv)
{
struct dirent *read;
char dir[400], error_message[400], format, hidden;
int i, j, dir_count, max_src_bytes = 397;
dir_list_t *dir_list, *dir_node;
file_list_t *file_list;
DIR *dirp;
int errno;
format = ' ';
hidden = ' ';
dir_count = 0;
strcpy(dir, ".");
for (i = 1; i < argc; i++)
{
if (argv[i][0] == '-')
{
for (j = 1; argv[i][j]; j++)
{
if (argv[i][j] == '1')
format = '1';
else if (argv[i][j] == 'l')
format = 'l';
if (argv[i][j] == 'a')
hidden = 'a';
else if (argv[i][j] == 'A')
hidden = 'A';
}
}
else
{
memset(dir, 0, strlen(dir));
strcpy(dir, argv[i]);
dir_list = add_dir_list(&dir_list, dir);
dir_count++;
}
}
if (dir_count == 0)
dir_list = add_dir_list(&dir_list, dir);
for (dir_node = dir_list; dir_node != NULL; dir_node = dir_node->next)
{
dirp = opendir(dir_node->dir);
if (dirp == NULL)
{
strcpy(error_message, "hls: cannot access ");
max_src_bytes = 381;
perror(strncat(error_message, dir_node->dir, max_src_bytes));
return (errno);
}
if (dir_count > 1)
printf("%s:\n", dir_node->dir);
while ((read = readdir(dirp)) != NULL)
{
file_list = add_file_list(&file_list, read->d_name);
}
switch (format)
{
case '1':
print_ls(hidden, '\n', file_list);
break;
case 'l':
print_ls(hidden, '\n', file_list);
break;
default:
print_ls(hidden, '\t', file_list);
}
if (dir_node->next != NULL)
putchar('\n');
free_file_list(&file_list);
}
free_dir_list(&dir_list);
closedir(dirp);
return (0);
}
/**
* print_ls - print contents in the default ls format, i.e. columns
*
* #hidden: parameter denoting the option for revealing hidden files
* #format: printing format parameter
* #dirp: pointer to the directory data
*
* Return: 0 for success, 1 for failure
*/
int print_ls(char hidden, char format, file_list_t *file_list)
{
file_list_t *file_node;
for (file_node = file_list; file_node != NULL; file_node = file_node->next)
{
if (hidden == 'a')
{
printf("%s", file_list->file);
if (file_list->next != NULL)
putchar(format);
}
else if (hidden == 'A')
{
if (strcmp(file_list->file, ".") != 0 &&
strcmp(file_list->file, "..") != 0)
{
printf("%s", file_list->file);
if (file_list->next != NULL)
putchar(format);
}
}
else
{
if (file_list->file[0] != '.')
{
printf("%s", file_list->file); // (line 139)
if (file_list->next != NULL)
putchar(format);
}
}
}
if (format == '\t')
printf("\n");
return (0);
}
add_file_list():
/**
* add_file_list - add a new node at the start of a file_list_t linked list
*
* #head: start of linked list
* #file: file data to add to node
*
* Return: address of new node; NULL if failure
*/
file_list_t *add_file_list(file_list_t **head, const char file[256])
{
file_list_t *node;
node = malloc(sizeof(file_list_t));
if (node == NULL)
return (NULL);
strcpy(node->file, file);
node->next = *head;
node->prev = NULL;
*head = node;
return (node);
}
I'm thinking about trying this out with an array of pointers instead, but I don't want to throw away my code before getting some insight. Am I not inputting the data into the node correctly? If so, how would I do that?
this is wrong, just as valgrind says
file_head = file_list; <<<< file_list is not initlaized, file_head = junk
while ((read = readdir(dirp)) != NULL)
{
printf("read: %s\n", read->d_name);
append_file_list(&file_list, read->d_name);
printf("file_list: %s\n", file_list->file);
}
printf("file_head: %s\n", file_head->file); <<<<<= (line 78) file_head = junk

C read linked list from file and write to another file

I'm trying to make a program that would read a linked list and output all of the info that it has read. My problem is that I can't simply output. There is some problem that I can't find.
#include <stdio.h>
#include <stdlib.h>
struct sarasas
{
char *reiksme;
struct sarasas *kitas;
};
int main()
{
struct sarasas *sarasasPtr, *pradz, *pab, *elem;
pradz = NULL;
pab = NULL;
FILE *duomPtr;
printf("Iveskite duomenu failo pavadinima: ");
char failas[255];
scanf("%s", failas);
duomPtr = fopen(failas, "r");
if(duomPtr == NULL)
{
printf("Toks duomenu failas neegzistuoja \n");
exit(0);
}
int k = 0;
char paimtaReiksme[255];
while(fscanf(duomPtr, "%s", paimtaReiksme) != EOF)
{
if(k == 0)
{
sarasasPtr = (struct sarasas*)malloc (sizeof (struct sarasas));
sarasasPtr->reiksme = paimtaReiksme;
sarasasPtr->kitas = NULL;
pradz = sarasasPtr;
pab = sarasasPtr;
}
else
{
sarasasPtr = (struct sarasas*)malloc (sizeof (struct sarasas));
sarasasPtr->reiksme = paimtaReiksme;
sarasasPtr->kitas = NULL;
pab->kitas = sarasasPtr;
pab = sarasasPtr;
}
k++;
}
if(pradz == NULL && pab == NULL)
{
printf("Tuscia\n");
exit(0);
}
FILE *rptr;
printf("Iveskite rezultatu failo pavadinima: ");
char failas2[255];
scanf("%s", failas2);
rptr = fopen(failas2, "w");
while(sarasasPtr->kitas != NULL)
{
fprintf(rptr, "%s", sarasasPtr->reiksme);
}
return 0;
}
You have an infinite loop in your code.
while(sarasasPtr->kitas != NULL)
{
fprintf(rptr, "%s", sarasasPtr->reiksme);
}
Here in the above while loop, you are trying to print the same element over and over again and thus you end up in an infinite loop.instead, you must change the pointer to next element after each and every iteration. You can try something like this:
while(sarasasPtr != NULL) //check whether pointer points to NULL
{
fprintf(rptr, "%s", sarasasPtr->reiksme);
sarasasPtr = sarasasPtr->kitas; //make pointer point to next element
}
additionally, you need not cast the the return value of malloc : Here's why(click)

Reading words from file error

I've got a problem with reading words from file and passing it to binary tree. When I debug it, it says:
Unhandled exception at 0x76E7773B(ntdll.dll) in Projekt.exe: 0.C00000005:
Access violation reading location 0x0037902A.
Here is the source code:
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
typedef struct Tree {
int val;
char *word;
struct Tree *left;
struct Tree *right;
} Tree;
void show(Tree *hd) {
if (hd != NULL) {
show(hd->left);
show(hd->right);
printf("%s -- %d\n", hd->word, hd->val);
}
}
void zero(Tree *aTree) {
if (aTree == NULL)
return;
zero(aTree->left);
free(aTree);
zero(aTree->right);
}
int alpha(char *word1, char *word2) {
if (word1[0] == 0 && word2[0] == 0)
return 2;
else
if (word1[0] == word2[0])
return alpha(&word1[1], &word2[1]);
else
if (word1[0] < word2[0])
return 1;
else
return 0;
}
Tree *create(char *word) {
Tree *temp;
temp = (Tree*)malloc(sizeof(Tree));
temp->left = temp->right = NULL;
temp->val = 1;
temp->word = (char*)malloc(sizeof(char));
strcpy(temp->word, word);
return temp;
}
Tree *insert(Tree *aTree, char *word) {
if (aTree == NULL) {
aTree = create(word);
} else
if (alpha(aTree->word, word) == 0) {
aTree->left = insert(aTree->left,word);
} else
if (alpha(aTree->word, word) == 1) {
aTree->right = insert(aTree->right, word);
} else
if (alpha(aTree->word, word) == 2) {
aTree->val++;
}
return aTree;
}
int main(int argc, char *argv[]) {
Tree *myTree = NULL;
char buffer[256] = { 0 };
char temp = 0;
int i = 0;
FILE *fp = fopen(argv[1], "r");
if (fp) {
while (temp != EOF) {
temp = getc(fp);
temp = toupper(temp);
if (temp >= 65 && temp <= 90) {
buffer[i] = temp;
i++;
} else {
if (buffer[0] != 0) {
puts(buffer);
myTree = insert(myTree, buffer);
memset(buffer, 0, sizeof(buffer));
i = 0;
}
}
}
}
fclose(fp);
show(myTree);
return 0;
}
Your program has several problems:
in function zero, you free the pointer too soon, you should move the free(aTree); as the last statement, otherwise you invoke undefined behavior, possibly a crash (but not the one you have, since you never call this function):
void zero(Tree *aTree) {
if (aTree != NULL) {
zero(aTree->left);
zero(aTree->right);
free(aTree);
}
In function alpha, you use recursion where a simple loop would suffice. The compiler may convert this to a loop, but it does have to. This is not a bug but why not use a more idiomatic approach such as:
int alpha(const char *word1, const char *word2) {
for (size_t i = 0;; i++) {
if (word1[i] == '\0' && word2[i] == '\0')
return 2;
if (word1[i] == word2[i])
continue;
if (word1[i] < word2[i])
return 1;
else
return 0;
}
}
In function create, you allocate a single byte for the string, this is definitely a cause for the crash. You should allocate strlen(word) + 1 or use strdup(word). You should not cast the return value of malloc() either:
Tree *create(const char *word) {
Tree *temp;
temp = malloc(sizeof(Tree));
temp->left = temp->right = NULL;
temp->val = 1;
temp->word = strdup(word);
return temp;
}
In function insert you call alpha multiple times, this is inefficient: you could use a switch statement:
Tree *insert(Tree *aTree, const char *word) {
if (aTree == NULL) {
return create(word);
switch (alpha(aTree->word, word)) {
case 0:
aTree->left = insert(aTree->left, word);
break;
case 1:
aTree->right = insert(aTree->right, word);
break;
case 2:
aTree->val++;
break;
}
}
return aTree;
}
function main has multiple issues:
You do not check if argv[1] is provided to the program. It would be NULL if the program is run without a command line argument.
Your test for end of file is incorrect: temp should be defined as int and you should test its value after reading the byte from the file with getc(), it is idiomatic to name c a variable used for this.
You should use character literals instead of hard coded ASCII values.
the test if (c >= 'A' && c <= 'Z') would work for ASCII, which is almost universal today, but it is more reliable to use isupper(c) instead.
You do not need to clear the buffer, setting a '\0' at the end before inserting the word is enough.
You should also check for buffer overflow and refuse to handle words longer than 255 characters.
You should not call fclose(fp) when fp is NULL, this is undefined behavior.
Here is a corrected version:
int main(int argc, char *argv[]) {
Tree *myTree = NULL;
char buffer[256];
int c;
size_t i;
FILE *fp;
if (argc < 2) {
printf("missing argument\n");
return 2;
}
fp = fopen(argv[1], "r");
if (fp == NULL) {
printf("cannot open %s\n", argv[1]);
return 1;
}
i = 0;
while ((c = getc(fp)) != EOF) {
c = toupper(c);
if (isupper(c)) {
if (i < sizeof(buffer))
buffer[i] = c;
i++;
} else {
if (i > 0 && i < sizeof(buffer)) {
buffer[i] = '\0';
puts(buffer);
myTree = insert(myTree, buffer);
i = 0;
}
}
}
fclose(fp);
show(myTree);
return 0;
}

Read word from file into simple linked list

I need to write a program to read from a file, then save the words into a linked list for further use. I decided to read the text character by character using fgetc, then save all into the list each time a newline ('\n') or space (' ') is detected, indicating one word.
Sorry I'm a newbie in file pointers, this is what I've gotten so far:
struct list { //global
char string[30];
struct list *next;
};
int main(void) {
FILE *filePtr;
char file[] = "text.txt";
char tempStr[30];
list *curr, *header;
char c;
int i = 0;
curr = NULL;
header = NULL;
if((filePtr = fopen(file, "r")) == NULL) {
printf("\nError opening file!");
getchar();
exit(101);
}
printf("\nFile is opened for reading.\n");
while(!EOF) {
while((c = fgetc(filePtr) != ' ') && (c = fgetc(filePtr) != '\n')) {
curr = (list*)malloc(sizeof(list));
//c = fgetc(filePtr);
tempStr[i] = fgetc(filePtr);
i++;
}
tempStr[i] = '\0';
strcpy(curr->string, tempStr);
curr->next = header;
header = curr;
i = 0;
}
while(curr!=NULL) {
printf("%s - ", curr->string); //This will not print.
curr = curr->next;
}
if(fclose(filePtr) == EOF) {
printf("\nError closing file!");
getchar();
exit(102);
}
printf("\nFile is closed.\n");
getchar();
getchar();
}
If the text file:
have a nice day
Desired output:
have - a - nice - day
But, I could not print out anything except the file opened and closed.
Thanks.
Value of the macro EOF is -1, which is a system macro defined in stdio.h. File read APIs(fgetc, fread, fscanf) will return -1 once it reaches end of file. So in your program you have while(!EOF) this will be always false, because NOT of -1 is always 0. -1 will be represented in 2's complement so all bits of that variable will be 1. (If size of int is 2, -1 will be stored as 0xFFFF in int variable).
Use the below sample code.
while(EOF != (c = fgetc(filePtr)))
{
if ((c == ' ') || (c == '\n'))
{
if (i == 0)
{
continue;
}
tempStr[i] = '\0';
i = 0;
//here do your linklist node creation and insertion operation
continue;
}
tempStr[i] = c;
i++;
}
while(!EOF) {
This is a constant condition that is always false, so you never read anything.
Your code also has other problems, such as doing
curr = (list*)malloc(sizeof(list));
in a loop but using curr outside the loop.
You should replace the while condition with whatever function you're using to read the file - are you sure fgets isn't horrendously more efficient than this?
IE read the string into a much larger buffer than you expect, then copy it into an appropriately sized buffer and attach that to the node.
This is always false:
while(!EOF)
Review your memory allocation code.
curr = (list*)malloc(sizeof(list))
Files may not have newlines at the end of the file.
while((c = fgetc(filePtr) != ' ') && (c = fgetc(filePtr) != '\n'))
Spoiler:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct list {
struct list *next;
char string[30];
};
int main(void) {
FILE *fp;
char file[] = "llist4.c";
/* in C you CANNOT omit the "struct keyword" from a declaration or definition. */
struct list *head=NULL, **pp= &head;
int ch; /* getc() returns an int */
size_t len ;
char buff[30];
fp = fopen(file, "r");
if (!fp) {
fprintf(stderr, "\nError opening file!");
exit(EXIT_FAILURE);
}
printf("\nFile has been opened for reading.\n");
for (len=0; len < sizeof buff; ) {
ch = fgetc(fp);
if (ch == EOF && !len) break;
if (ch == ' ' || ch == '\n' || ch == EOF) {
if (!len) continue;
buff[len] = '\0';
*pp = malloc(sizeof **pp);
if (!*pp) break;
strcpy((*pp)->string, buff);
(*pp)->next = NULL;
pp = &(*pp)->next ;
len=0; continue;
}
buff[len++] = ch;
}
if (len) {
fprintf(stderr, "\nWord was too large, or out of memory\n");
}
for( ;head; head= head->next) {
printf("%s - ", head->string);
}
if (fclose(fp) == EOF) {
fprintf(stderr, "\nError closing file!\n");
exit(EXIT_FAILURE);
}
printf("\nFile has been closed.\n");
exit(EXIT_SUCCESS);
}

Resources