fscanf to a linked list - c

I'm in trouble with my code again.
I want to fscanf result.txt to structures with linked list, but it don't work;
I think the simply linked list must be enought;
The problem is: the program just write the first line, but nothing else.
result.txt format:
point name (for examples)
623 john
457 peter
312 chuck
etc.
The code:
#include <stdio.h>
#include <stdlib.h>
typedef struct ranklist {
int point;
char* name;
struct ranklist *next;
} ranklist;
int how_many_records(FILE *fp){
char ch;
int line=0;
int status;
rewind(fp);
while((status=fscanf(fp, "%*d %*[^\n]%c", &ch))==1)
++line;
if(status != EOF){
++line;
}
rewind(fp);
return line;
}
int how_many_letter(FILE *fp){
int letter = 0;
long pos = ftell(fp);
//fscanf(fp, " %*[^\n]%n", &letter);
fscanf(fp, " %*s%n", &letter);
fseek(fp, pos, SEEK_SET);
return letter;
}
int main(void){
FILE *fp = fopen("result.txt","r");
int name_length;
int lines = how_many_records(fp);
ranklist *r = malloc(lines * sizeof(*r));
ranklist *first = r;
for ( r=first ;r != NULL; r = r->next){
fscanf(fp, "%d", &(r->point));
name_length = how_many_letter(fp);
r->name = malloc(name_length + 1);
fscanf(fp,"%s", r->name);
}
fclose(fp);
for ( r=first ;r != NULL; r = r->next){
printf("%d %s\n", r->point, r->name);
}
free(r);
return 0;
}

fscanf(fp, "%d", &r[y].point);
Here, y is uninitialized.
You need to put y = 0, or, IMO, better to use &(r->point) [and the same goes for r[y].name also]
Suggestion: for reading and parsing whole lines better to use fgets()

You have multiple problems with the creation of the list.
Lets start with the loop:
for ( r=first ;r != NULL; r = r->next){
Nowhere in the loop do you initialize r->next, so after the first iteration you will make y point to totally random memory, leading to undefined behavior.
As mentioned in another answer you don't initialize the variable y, which is another cause of undefined behavior.
You also change r, so r will not point to the original memory you allocated so doing r[y] is a third cause of undefined behavior.
And after the loop you call free with the modified pointer y, which will also lead to undefined behavior. And you don't free the names you allocate in the loop, so have multiple memory leaks as well.
There is no need to pre-allocate the nodes at all, just allocate when needed.
Something like
ranklist *head = NULL;
FILE *fp = fopen(...);
// Read the file and create the list
char buffer[256];
while (fgets(buffer, sizeof(buffer), fp) != NULL)
{
ranklist *node = malloc(sizeof(ranklist));
node->name = malloc(strlen(buffer)); // Will allocate a little more than needed
sscanf(buffer, "%d %s", &node->point, node->name);
node->next = head;
head = node;
}
// Print the list
for (ranklist *n = head; n != NULL; n = n->next)
{
printf("%d %s\n", n->point, n->name);
}
// Free the list
while (head != NULL)
{
// Unlink the first node in the list
ranklist *n = head;
head = n->next;
// And free it
free(n->name);
free(n);
}
The code above doesn't have any error checking, it also have some overhead when allocating space for the name, but it will be safe, it will not handle unrealistically long names, and the list will actually be a stack (last item read will be first in the list).
Function to get the length of the name from the buffer read with fgets:
size_t get_name_length(char *buffer)
{
// Since the buffer was read with `fgets` we need to get rid
// of the newline at the end, if it's there
size_t length = strlen(buffer);
if (buffer[length - 1] == '\n')
buffer[length - 1] = '\0'; // "Remove" by terminating the string
// Find the space dividing the point and the name
char *space = strchr(buffer, ' ');
// Just in case there are multiple whitespace characters in the string
while (*space != '\0' && isspace(*space))
++space;
// Now `space` points to the first non-space letter in the name
// (or to the string terminator, if there's no name
// Then length of the name is the remainder of the string
return strlen(space);
}

FILE *fp = fopen("result.txt","r");
int name_length;
//Just create a link if you use as an array
//int lines = how_many_records(fp);
//ranklist *r = malloc(lines * sizeof(*r));
ranklist *first=NULL, *curr, *r;
int point;
while(1==fscanf(fp, "%d", &point)){
r = malloc(sizeof(*r));//allocate one record
r->next = NULL;
r->point = point;
name_length = how_many_letter(fp);
r->name = malloc(name_length + 1);
fscanf(fp, "%s", r->name);
//make link
if(first == NULL)
first = curr = r;
else
curr = curr->next = r;
}
fclose(fp);
for (r = first; r != NULL; r = r->next){
printf("%d %s\n", r->point, r->name);
}
for (r = first; r != NULL; ){
ranklist *tmp = r->next;//Save next for free(r)
free(r->name);
free(r);
r = tmp;
}
//output the list
void print(ranklist *first){
while(first != NULL){
printf("%d %s\n", first->point, first->name);
first = first->next;
}
}

Related

Problem with pointers to three different linked list

I'm having problem with pointers in a C program that count the occurrences of a string or more in a bunch of file. The program take in input a file which contains the paths of the files in which search the occurrences. All the files that i will mention are contained in the same folder of the project, whose name is "find". In my case, the input file is "path.txt":
C:\Users\Utente\Desktop\find\try.txt
C:\Users\Utente\Desktop\find\try1.txt
The try.txt content is:
abc
abc
abc
ac
ac
ac
ac
The try1.txt content is:
ac
ac
ac
ac
abc
abc
abc
My program is composed by 4 files, two header-files and two source files:
find.c:
#include "find.h"
int main(int argc, char * argv[]){
FILE *fInput = NULL;
FILE *fp = NULL;
char *line1;
char *line2;
int endOfLineDetected = 0;
size_t nrOfCharRead = 0;
char ch;
fWord *w = NULL;
fWord *start = NULL;
fWord *tail = NULL;
fPath *head = NULL;
fPath *current = NULL;
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);
fPath *node = malloc (sizeof(fPath));
node->path = line1;
node->fileOccurrences = 0;
node->position = NULL;
node->next = NULL;
if(head == NULL){
current = head = node;
}else{
current = current->next = node;
}
}
fclose(fInput);
//create a linked list of the type fWord, one structure for each word.
do{
fWord *app = malloc(sizeof(fWord));
printf("Insert the word to search: ");
scanf("%s", app->word);
app->totalOccurences = 0;
app->p = head;
app->next = NULL;
if(start == NULL){
tail = start = app;
}else{
tail = tail->next = app;
}
printf("Do you want to insert another word? (Y/N): ");
scanf(" %c", &ch);
}while(ch == 'y' || ch == 'Y');
w = start; //pointer back to the top of the fWord structure
//traverse all the structure and execute the algorithm
while(w != NULL){
while(w->p != NULL){
fp = fopen(w->p->path, "r");
if(fp == NULL){
fprintf(stderr, "Cannot open %s, exiting. . .\n", w->p->path);
exit(1);
}
int countLine = 0;
w->p->fileOccurrences = 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(); // //pointer back to the top of the fPosition structure
w->p = w->p->next;
fclose(fp);
}
w->p = head; //pointer back to the top of the fPath structure
}
w = start; //pointer back to the top of the fWord structure
//traverse all the structure and print out the occurrences and their position
while(w != NULL){
w->p = head;
printf("WORD %s \r\n", w->word);
printf("TOTAL %d \r\n", w->totalOccurences);
while(w->p != NULL){
printf("FILE %s \r\n", w->p->path);
printf("OCCURENCES %d \r\n", w->p->fileOccurrences);
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 = w->p->next;
}
w = w->next;
}
printf("\r\n"); //the file ends with an empty line
return 0;
}
//method used for read 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 up 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
}
find.h:
#include "kmp.h"
char * getLineOfAnySize(FILE* fp, size_t typicalSize, int *endOfLineDetected,size_t *nrOfCharRead);
kmp.c:
#include "kmp.h"
fPosition *head = NULL;
fPosition *current = NULL;
// 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; //count the occurrences of the string in this file
fPosition *node = malloc (sizeof(fPosition));
node->line = line; //the current line
node->character = i - j + 1; //the shift in which occurs
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; //return the number of occurences found
}
//take the pointer back to the top of fPosition
fPosition * getHead(){
fPosition *app = head;
head = NULL;
return app;
}
kmp.h:
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
struct filePath{
char *path; //the file path
struct filePath *next;
};
struct OccurrencesPosition{
int line; //line in which an occurrence is founded
int character; //shift at which the occurrences comes
struct filePath pathInfo;
struct OccurrencesPosition *next; //pointer to the next occurrences
};
struct fileWord{
char word[50]; //the string to search
int totalOccurences; //the total occurrences of the string
int fileOccurrences; //the occurrences of each file
struct OccurrencesPosition *position; //pointer to the linked list which tracks all the occurrences and their positions
struct fileWord *next; //pointer to the next word
};
typedef struct filePath fPath;
typedef struct fileWord fWord;
typedef struct OccurrencesPosition fPosition;
fPosition * getHead();
int KMP(const char* X, const char* Y, int m, int n, int line, fPath *app);
The problem is that when i run my program passing in input "abc" and "ac" it returns wrong value. More precisely, returns the value corresponding to "ac" in both cases. Here's the execution:
PS C:\Users\Utente\Desktop\find> gcc find.c kmp.c -o "find.exe"
PS C:\Users\Utente\Desktop\find> .\find.exe "path.txt"
Insert the word to search: abc
Do you want to insert another word? (Y/N): Y
Insert the word to search: ac
Do you want to insert another word? (Y/N): N
WORD abc
TOTAL 6
FILE C:\Users\Utente\Desktop\find\try.txt
OCCURENCES 4
3 0
4 0
5 0
6 0
FILE C:\Users\Utente\Desktop\find\try1.txt
OCCURENCES 4
0 0
1 0
2 0
3 0
WORD ac
TOTAL 8
FILE C:\Users\Utente\Desktop\find\try.txt
OCCURENCES 4
FILE C:\Users\Utente\Desktop\find\try1.txt
OCCURENCES 4
As you can see, the WORD and TOTAL are correct in both cases, but the occurrences not. They correspond to "ac" in both cases.
The correct output should be:
WORD abc
TOTAL 6
FILE C:\Users\Utente\Desktop\find\try.txt
OCCURENCES 3
0 0
0 1
0 2
FILE C:\Users\Utente\Desktop\find\try1.txt
OCCURENCES 3
4 0
5 0
6 0
WORD ac
TOTAL 8
FILE C:\Users\Utente\Desktop\find\try.txt
OCCURENCES 4
3 0
4 0
5 0
6 0
FILE C:\Users\Utente\Desktop\find\try1.txt
OCCURENCES 4
0 0
1 0
2 0
3 0
I think that the problem is with the fPosition pointers. Thanks to anyone who helps.
You have design issue.
The problem is occurrences info you are maintaining as part of filePath list.
struct filePath{
char *path; //the file path
int fileOccurrences; //the occurrences of each file
struct OccurrencesPosition *position; // here *****************
struct filePath *next;
};
And file path info you are maintaining as part of fileWord list.
struct fileWord{
char word[50]; //the string to search
int totalOccurences; //the total occurrences of the string
struct filePath *p; //pointer to the linked list of all the files
struct fileWord *next; //pointer to the next word
};
Since you only have one file path list, each word in fileWord list is actually pointing to same filepath list.
Every word is pointing to same file path list
fWord *app = malloc(sizeof(fWord));
printf("Insert the word to search: ");
scanf("%s", app->word);
app->p = head; //here
and you are updating the position info inside the filepath for every word.
w->p->position = getHead(); // //pointer back to the top of the fPosition structure
Thus filePath list is holding position info only for the latest word you search.
Update:
Your design should look as below.
struct filePath{
char *path; //the file path
struct filePath *next;
};
struct OccurrencesPosition{
int line; //line in which an occurrences is founded
int character; //shift at which the occurrences comes
struct filePath pathInfo;
struct OccurrencesPosition *next; //pointer to the next occurrences
};
struct fileWord{
char word[50]; //the string to search
int totalOccurences; //the total occurrences of the string
int fileOccurrences; //the occurrences of each file
struct OccurrencesPosition *position; //pointer to the linked list which tracks all the occurrences and their positions
struct fileWord *next; //pointer to the next word
};

How to avoid buffer overflow with C struct array of strings

I'm running into buffer overflows when reading a file in C and copying character arrays. There are three potentially offending pieces of code and I can't figure out where I'm going wrong.
The first reads a file and populates it into a hashmap:
bool load_file(const char* in_file, hmap hashtable[]) {
for(int x = 0; x < HASH_SIZE; x++) {
hashtable[x] = NULL;
}
FILE *fptr = fopen(in_file, "r");
char c[LENGTH] = "";
c[0] = '\0';
while (fgets(c, sizeof(c)-1, fptr) != NULL) {
node *n = malloc(sizeof(node));
hmap new_node = n;
new_node->next = NULL;
strncpy(new_node->content, c, LENGTH-1);
// do stuff to put it into the hashtable
}
fclose(fptr);
return true;
}
The second checks whether given content is in the hashmap:
bool check_content(const char* content, hmap hashtable[]) {
char c_content[LENGTH] = "";
strncpy(c_content, content, LENGTH-1);
// do stuff to check if it's in the hashmap
return false;
}
and the third parses a given file and checks whether its content is in the hashmap:
int check_file(FILE* fp, hmap hashtable[], char * not_found[]) {
int num_not_found = 0;
char c[1000] = "";
while (fgets(c, sizeof(c)-1, fp) != NULL) {
char * pch;
char curToken[LENGTH] = "";
pch = strtok (c," ");
strncpy(curToken, pch, LENGTH-1);
curToken[LENGTH]=0;
if(!check_content(curToken, hashtable)) {
not_found[num_not_found] = malloc(LENGTH*sizeof(not_found[num_not_found]));
strncpy(not_found[num_not_found], curToken, LENGTH-1);
num_not_found++;
}
}
fclose(fp);
return num_not_found;
}
Finally, main calls these and frees mallocs:
int main (int argc, char *argv[])
{
hmap hashtable[HASH_SIZE];
load_file(argv[2], hashtable);
FILE *fptr = fopen(argv[1], "r");
char * not_found[MAX_ENTRIES];
int num_not_found = check_file(fptr, hashtable, not_found);
for(int x=0; x<num_not_found; x++) {
free(not_found[x]);
}
for(int y=0; hashtable[y] != NULL; y++) {
free(hashtable[y]);
}
return 0;
}
My question is this: for each of the three code snippets, what have I done that causes buffer overflows? Many thanks in advance!
I finally got rid of the buffer overflow problems mostly by following David's advice in the comments, plus figuring out that I had one more malloc than I needed. The fixes were:
new_node->next needed a malloc
The malloc for new_node->next should happen only if it's actually going to be used.
not_found[num_not_found] = malloc(LENGTH*sizeof(not_found[num_not_found])); was wrong and should have been notfound[num_not_found] = malloc(sizeof(char) * (strlen(pch)+1)) (assuming pch wasn't null terminated). (Side note, for whatever reason, on my computer, malloc(sizeof(char) * strlen(pch)+1) is not the same as malloc(strlen(pch)+1))
The return of every malloc really does have to be validated.

Need some help in my C program,I've got a segmentation fault but I don't know why

I was trying to create a single linked list that contains some words from a .txt file on my desktop, but when I run it in terminal, I got a segmentation fault. Later I compiled the code on Xcode and run it, I got this error message:
Thread 1:EXC_BAD_ACCESS(code=1, address=0x7fff5fc00000)
I'm a beginner, and I really need some help now. Thanks!
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct word{
int num;
char word[50];
struct word *next;
} Word;
#define len sizeof(Word)
Word *create();
void print(Word *head);
int main()
{
Word *head;
head = create();
print(head);
return 0;
}
Word *create()
{
Word *head, *p1, *p2;
char word[50], c;
int i = 0;
FILE *fp = fopen("/Users/apple/Desktop/words", "r");
head = p1 = p2 = NULL;
while(fp != NULL){
i = 0;
p1 = (Word *)malloc(len);
//get the English word
while((c = fgetc(fp)) != '\n'){
word[i++] = c;
}
word[i] = '\0';
strcpy(p1->word, word);
p1->next = NULL;
if(head == NULL){
head = p1;
p2 = p1;
} else {
p2->next = p1;
p2 = p1;
}
p1 = p1->next;
}
return head;
}
void print(Word *head)
{
Word *p = head;
while(p != NULL){
printf("%s\n", p->word);
p = p->next;
}
}
And this is the content of the .txt file:
Before your question gets deleted, here are some incorrect things that you are doing in your code and you should take a look at it even before you try to fix your segfault.
while(fp != NULL){
i = 0;
p1 = (Word *)malloc(len);
That's not how you read from a file. The file pointer fp is not expected change. If you want to know whether your file has finished, you have to check the output of the read functions. fscanf() and fgetc() return EOF when you try to read past the last character of the file.
Also, do not use feof(). It's almost always wrong.
while((c = fgetc(fp)) != '\n'){
word[i++] = c;
}
fgetc() returns an (int), so you should declare int c. That's how you check if you have read everything. After you read the last word, fgetc() will return EOF. It is usually -1, but, regardless of its value, it doesn't fit into a (char). You need (int).
Also, you should be using fscanf() instead of reading it char-by-char (unless it is your assignment to do so). fscanf() reads until the end of the word and adds a 0 automatically.
This
p1 = (Word *)malloc(len);
will not help you. That len is not doing you any favors. Neither is (Word*). This is how you should do:
p1 = malloc(sizeof (Word));
or even better
p1 = malloc(sizeof *p1);
The last one doesn't even require you to know the type of p1.

Outputting a string from a structure

I am trying to create a program that takes input from a file, puts each word into a "words" structure, and then outputs the results with the frequency of each word, but whenever I try to output the string it just prints something like ?k#?? where I would expect the string to be.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct s_words {
char *str; //stores the word; no pre-determined size
int count;
struct s_words* next;
} words;
words* create_words(char* word) {
//allocate space for the structure
words* newWord = malloc(strlen(word));
if (NULL != newWord){
//allocate space for storing the new word in "str"
//if str was array of fixed size, storage wud be wasted
newWord->str = (char *)malloc(strlen(word));
strcpy(newWord->str,word); //copy “word” into newWord->str
newWord->str[strlen(word)]='\0';
newWord->count = 1; //initialize count to 1;
newWord->next = NULL; //initialize next;
}
return newWord;
}
//If the word is in the list, add 1 to count.
words* add_word(words* wordList, char* word) {
int found=0;
words *temp=wordList;
// search if word exists in the list; if so, make found=1
while (temp!=NULL) {
// printf("looptest\n");
if (strcmp(word,temp->str) == 0) { //use strcmp command
//printf("looptest0\n");
found=1;
temp->count = temp->count + 1; //increment count;
return wordList;
//printf("looptest1\n");
}
else {
temp = temp -> next; //update temp
// printf("looptest2\n");
}
}
// printf("looptest3\n");
//new word
words* newWord = create_words(word);
// printf("looptest4\n");
if (NULL != newWord) {
// printf("looptest5\n");
newWord->next = wordList;
wordList = newWord;
//Insert new word at the head of the list
}
else{
// printf("looptest6\n");
temp = wordList;
while(temp->next != NULL){
// printf("looptest7\n");
temp = temp->next;
}
temp->next = newWord;
}
return newWord;
}
int main(int argc, char* argv[]) {
words *mywords; //head of linked list containing words
mywords=NULL;
FILE *myFile;
myFile = fopen(argv[1],"r"); //first parameter is input file
if (myFile==0) {
printf("file not opened\n");
return 1;
}
else {
printf("file opened\n");
}
//start reading file character by character;
//when word has been detected; call the add_word function
int ch, word = 0, k=0;
char thisword[100];
while ( (ch = fgetc(myFile)) != EOF )
{
// printf("%c",ch);
if (ch==' ' || ch==',' || ch==';' || ch==':' || ch == '.') //detect new word? Check if ch is a delimiter
{
// printf("\ncheck2\n");
if ( word ) //make sure previous character was not delimiter
{
// printf("check\n");
word = 0;
thisword[k] = '\0'; //make the kth character of thisword as \0
// printf("test2\n");
//now call add_word to add thisword into the list
mywords = add_word(mywords,thisword);
// printf("check3\n");
k=0;
}
// printf("test\n");
}
else
{
word = 1;
thisword[k] = ch; //make the kth character of thisword equal to ch
k++;
}
if(ch == EOF){
thisword[k] = '\0';
mywords = add_word(mywords,thisword);
}
}
printf("%s\n",mywords->str);
printf("printing list\n");
//Traverse list and print each word and its count to outputfile
//output file is second parameter being passed
//haven't started to deal with the output file
words* temp = mywords;
while(temp != NULL){
printf("%s\tcount: %i\n",temp->str,temp->count);
temp = temp->next;
}
printf("list complete\n");
return 0;
}
This is all my code, I can't figure out how to error test what the problem is since I can't figure out how to output the strings. I've only started programming in C this year so I assume there's something basic I'm missing.
newWord->str = (char *)malloc(strlen(word));
strcpy(newWord->str,word); //copy “word” into newWord->str
newWord->str[strlen(word)]='\0';
.. writes the null out-of-bounds.
Assuming that strlen() returns the desired value, you should malloc an extra char:
newWord->str = (char *)malloc(1+strlen(word));
Note Olaf comment re. casting in C. Also note that it's unlikely that this is your ONLY bug.

Segmantation Fault in C

This program will create link list from text alphabetically.
It is case-sensitive and it will eliminate the marks.
When I run the program, it gives a segmentation fault. I can't find where the problem is. I added the printf() in order to find the mistake but i can't.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
typedef struct NODE {
char *word;
int count;
struct NODE *next;
}NODE;
char *get_word(FILE *fp){
printf("getWord");
char *str = (char*)malloc(sizeof(char)*100);
char c;
do {
c = fgetc(fp);
if (c == EOF)
return 0;
} while (!isalpha(c));
do {
printf("getWord");
*str++ = tolower(c);
c = fgetc(fp);
printf("Word");
} while (isalpha(c));
return str;
}
void insert(NODE* sortedList, char *word) {
printf("INSERT ");
char *str = (char*)malloc(sizeof(char)*100);
if (sortedList == NULL || word < sortedList->word) {
NODE *ekle;
ekle=(NODE*)malloc(sizeof(NODE));
strcpy(ekle->word,word);
ekle->count = 1;
ekle->next = sortedList;
sortedList = ekle;
}
else {
//
NODE *current = sortedList->next;
NODE *pre = sortedList;
while (current != NULL && word > current->word) {
pre = current;
current = current->next;
}
if (current != NULL && word == current->word) {
(current->count)++;
}
else {
NODE *ekle;
ekle=(NODE*)malloc(sizeof(NODE));
strcpy(ekle->word,word);
ekle->count = 1;
ekle->next = current;
pre->next = ekle;
}
}
}
void createList(FILE* fp,NODE *n) {
printf("CREATELIST ");
char *word;
strcpy(word,get_word(fp));
puts(word);
while (strcmp(word,"")) {
printf("Create_LİST2");
insert(n,word);
word = get_word(fp);
}
}
NODE *head;
int main(){
NODE *list=NULL;;
FILE *fp;
fp=fopen( "text.txt", "r" );
head=list;
while(!feof(fp)){
createList(fp,list);
}
while(list->next != NULL){
printf("%s", list->word);
}
return 0;
}
A major problem is this line
*str++ = tolower(c);
This changes the pointer str, so when you return str from the function it actually points beyond the string. A string which you, by the way, do not terminate.
Another major problem are these lines:
NODE *ekle;
ekle=(NODE*)malloc(sizeof(NODE));
strcpy(ekle->word,word);
Here you allocate a NODE structure, but you do not allocate memory for ekle->word, so it points to indeterminate memory. You have the above code in two places.
Equal to the above allocation problem, you have
char *word;
strcpy(word,get_word(fp));
Here too you don't allocate memory for word, so you have a pointer to indeterminate memory.
Also, in C you should not cast the return of malloc. You should also look out for warnings from the compiler, and if you don't get any from the code you have then you need to enable more warnings. Compiler warnings are often a sign of undefined behavior which is what all of the above leads to. And finally, next to the compiler I would argue that a debugger is a developers best tool. Learn to use it, it would have helped you with some of the above problems.
Here's one problem:
char c;
do {
c = fgetc(fp);
if (c == EOF)
return 0;
This is wrong; fgetc() returns int, since EOF does not fit in a char. The first line should therefore be:
int c;
Fist you have to verify if the file is correctly open. Then AFAIK the strcpy requires that destination has enough space to store the data (line 74), instead of "char *word" use "char word[255]" for instance (if you know the size limit).
Your main problem is here:
*str++ = tolower(c);
First of all, once you increment str, you no longer hold a pointer to the dynamically allocated memory. Therefore, you will not be able to release that memory at a later point in the execution of your program, which will eventually lead to memory leaks. Second, when you return str at the end of the function, you are not returning a pointer to that string as you're probably hoping to.
Additional problems are:
You are not making sure that no more than 99 characters are stored.
You are not terminating the string pointed by str with a null-character.
You are not de-allocating the string pointed by str if an EOF is encountered.
You are not using an int in order to store the return value of function fgetc.
Here is how your function should look like:
#define MAX_WORD_LEN 101
char* get_word(FILE* fp)
{
char* str = (char*)malloc(sizeof(char)*MAX_WORD_LEN);
int c,i;
do
{
c = fgetc(fp);
if (c == EOF)
{
free(str);
return 0;
}
}
while (!isalpha((char)c));
i = 0;
do
{
str[i++] = tolower((char)c);
c = fgetc(fp);
}
while (isalpha((char)c) && i < MAX_WORD_LEN-1);
str[i] = 0;
return str;
}
Please note that if a word in your file is longer than MAX_WORD_LEN-1 characters, then you will essentially "lose" the last character that was read, because it will not be stored anywhere.
not the segfault, but: you malloc str, without using or freeing it
void insert(NODE* sortedList, char *word) {
printf("INSERT ");
char *str = (char*)malloc(sizeof(char)*100);
Here i write code which may helps you to understand problem. It's not exact what as your program does but somewhat similar and easier to understand and also find your all problems solution from below code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
typedef struct NODE
{
char word[100];
int count;
struct NODE *next;
}NODE;
NODE *head = NULL;
NODE *list = NULL;
void insert(char *word)
{
if (list == NULL)
{
list = calloc(1, sizeof(NODE));
if (NULL == list)
{
perror("Memory allocation failed");
return;
}
strncpy(list->word, word, 99);
list->count = 1;
list->next = NULL;
head = list;
}
else
{
list->next = calloc(1, sizeof(NODE));
if (NULL == list->next)
{
perror("Memory allocation failed");
return;
}
strncpy(list->next->word, word, 99);
list->next->count = 1;
list->next->next = NULL;
list = list->next;
}
}
void createList(FILE* fp)
{
char word[100] = {0};
while (EOF != fscanf(fp, "%99s", word))
{
if (0 < strlen(word))
{
insert(word);
}
memset(word, 0x00, 100);
}
}
int main()
{
FILE *fp = NULL;
fp = fopen("text.txt", "r");
if (NULL == fp)
{
//File is not readable
perror("text.txt file open failed");
return -1;
}
createList(fp);
list = head;
while(NULL != list)
{
printf("%s\n", list->word);
list = list->next;
}
if (NULL != fp)
{
fclose(fp);fp = NULL;
}
return 0;
}
And also create function to free all memory which is allocated in insert function.

Resources