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.
Related
I am having a problem with my code using malloc. It has been working perfectly until an hour before. It causes on this line
temp2 = (Temp*)malloc(sizeof(Temp));
I've tried removing (Temp*) to see if that helps but it didn't. And when I searched my error message which is
untitled8(15926,0x1141ae5c0) malloc: Incorrect checksum for freed object 0x7fbff3c032e8: probably modified after being freed.
Corrupt value: 0x742e7962616c6c61
untitled8(15926,0x1141ae5c0) malloc: *** set a breakpoint in malloc_error_break to debug
Signal: SIGABRT (signal SIGABRT)
The answers I found from the internet would something to do with free(), but it errored before when I free any malloced variables.
I have main.c and task1.c and task.2, also 3 header file, and the code below is from task1.c. Never wanted to post this long ass code but since I used malloc to the other part so I would like it to be checked as well... sorry for any inconvenience reading code in advance.
typedef struct histogramTemp {
char *words;
int count;
struct histogramTemp *next;
} HistogramTemp;
typedef struct temp{
char c;
struct temp *next;
} Temp;
HistogramTemp *task1(FILE *fp, char *fname){
char textfile, *string = NULL;
Temp *tempHead = NULL, *temp1, *temp2;
HistogramTemp *uniqueWordTemp = NULL, *headTemp, *uniqueWordTempHead = NULL;
if(fp == NULL){
printf("\n\n!! Error in opening file !!\n");
printf("Program will proceed with defult 'australia.txt' file. \n");
FILE *defultFp;
defultFp = fopen("/Users/katyang/CLionProjects/untitled8/australia.txt", "r");
fp = defultFp;
}
while((textfile = fgetc(fp))!=EOF){
// save temporary word as a separate char linked list 'Temp', and save it to 'string' as a whole word
if (isupper(textfile)>0) {
temp1 = (Temp*)malloc(sizeof(Temp));
temp1->c = textfile;
temp1->next = tempHead;
tempHead = temp1;
int i=0;
while(tempHead != NULL){
string = malloc(30*sizeof(char));
strcpy(&string[i],&tempHead->c);
i++;
tempHead = tempHead->next;
}
while ((textfile = fgetc(fp))!=EOF) {
if (isalpha(textfile)>0 && !(isupper(textfile))) {
temp2 = (Temp*)malloc(sizeof(Temp));
temp2->c = textfile;
temp2->next = tempHead;
tempHead = temp2;
while(tempHead != NULL){
strcpy(&string[i],&tempHead->c);
i++;
tempHead = tempHead->next;
}
}
// use 'string', make Histogram
if(isupper(textfile) || !isalpha(textfile)){
int flag=0;
int commonWordsFlag=0;
// check if the words are in the commonWords list
for (int j = 0; j < 122 ; j++) {
if (strcmp(string, commonwords[j])==0){
commonWordsFlag++;
break;
}
}
if((strlen(string)<3) || (commonWordsFlag == 1)){
break;
}
headTemp = uniqueWordTempHead;
// compare string to uniqueWordTemp
while (uniqueWordTempHead != NULL){
// increment count if the word is in Histogram
if(strcmp(uniqueWordTempHead->words, string)==0){
uniqueWordTempHead->count++;
flag++;
uniqueWordTempHead=uniqueWordTempHead->next;
}else{
uniqueWordTempHead=uniqueWordTempHead->next;
continue;
}
}
// create new node if the word is not in Histogram
if ((uniqueWordTempHead == NULL) && (flag == 0)){
uniqueWordTempHead = headTemp;
uniqueWordTemp = (HistogramTemp*)malloc(sizeof(HistogramTemp));
uniqueWordTemp->words = string;
uniqueWordTemp->count=1;
// insert in head
uniqueWordTemp ->next = uniqueWordTempHead;
uniqueWordTempHead = uniqueWordTemp;
}else{
uniqueWordTempHead = uniqueWordTemp;
}
break;
}
}
}
}
createNewFile(fname, uniqueWordTempHead);
free(string);
free(tempHead);
return(uniqueWordTempHead);
}
so, I expected to save data in temp2 a string. It seems working with debugging which is so strange.. I have no problem when I debugged but my program ended with exit code 11 every time when I execute the program.
Edit
I added a main.c and a header file of task1() for more information.
main.c
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
#include <math.h>
#include "task1.h"
#include "task2.h"
int main() {
FILE *fp;
char *fname = malloc(sizeof(char));
printf("\n\n:::::::::::::: TASK 1 ::::::::::::::\n\nPlease Enter the Full Path of the file: \n");
scanf("%s", fname);
fp = fopen( fname , "r");
task1(fp, fname);
HistogramTemp *uniqueWordTempHead = task1(fp, fname);
task2(fp, fname);
free(fname);
free(uniqueWordTempHead);
return 0;
}
header file
#ifndef UNTITLED8_TASK1_H
#define UNTITLED8_TASK1_H
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
typedef struct histogramTemp {
char *words;
int count;
struct histogramTemp *next;
} HistogramTemp;
typedef struct temp{
char c;
struct temp *next;
} Temp;
HistogramTemp *task1(FILE *fp, char *fname);
int countHistogram (HistogramTemp *head);
void printHistogram (HistogramTemp *head, FILE *fp);
void createNewFile(char *userFilename, HistogramTemp *head);
#endif //UNTITLED8_TASK1_H
You cannot append just a char to a "string" like this:
strcpy(&string[i],&tempHead->c);
strcpy() expects a pointer to a "string"'s 1st char as 2nd parameter. In C a "string" is an array of char with at least one char being equal to '\0'.
Use
string[i] = tempHead->c;
instead and terminate string by doing
string[i] = '\0';
Also here
while(tempHead != NULL){
string = malloc(30*sizeof(char));
string get allocate to with each iteration overwriting the point received in the previous iteration. This introduces a huge memory leak.
More the allocation out of the loop.
So this
while(tempHead != NULL){
string = malloc(30*sizeof(char));
strcpy(&string[i],&tempHead->c);
i++;
tempHead = tempHead->next;
}
would look like this
string = malloc(30*sizeof(char));
i = 0;
while(tempHead != NULL && i < 29){ // one less to be able to store the '0' terminator
string[i] = tempHead->c;
i++;
tempHead = tempHead->next;
}
string[i] = '\0'; // store the '0' terminator
So I have a program that receives as input a string with the format a word1 word2 word3 and that inserts these words into a structure that finally goes into a linked list. With all the inputs I have tried it works perfectly and there are no memory leaks but with this specific output I get a Segmentation Error as well as memory leak and it's almost surely because of the length of word1.
This is the input:
a
Adolph_Blaine_Charles_David_Earl_Frederick_Gerald_Hubert_Irvin_John_Kenneth_Lloyd_Martin_Nero_Oliver_Paul_Quincy_Randolph_Sherman_Thomas_Uncas_Victor_William_Xerxes_Yancy_Zeus_Wolfeschlegelsteinhausenbergerdorffwelchevoralternwarengewissenhaftschaferswessenschafewarenwohlgepflegeundsorgfaltigkeitbeschutzenvorangreifendurchihrraubgierigfeindewelchevoralternzwolfhunderttausendjahresvorandieerscheinenvonderersteerdemenschderraumschiffgenachtmittungsteinundsiebeniridiumelektrischmotorsgebrauchlichtalsseinursprungvonkraftgestartseinlangefahrthinzwischensternartigraumaufdersuchennachbarschaftdersternwelchegehabtbewohnbarplanetenkreisedrehensichundwohinderneuerassevonverstandigmenschlichkeitkonntefortpflanzenundsicherfreuenanlebenslanglichfreudeundruhemitnichteinfurchtvorangreifenvorandererintelligentgeschopfsvonhinzwischensternartigraum foo#bar.zp 2
Here's my code:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define MAXINPUT 682
typedef struct words {
char *word1;
char *word2;
char *word3;
} words;
typedef struct node{
words cont;
struct node *next;
} node;
typedef node *link;
link head;
void add(char c[]) {
words x;
char *str;
link temp = (link)malloc(sizeof(node));
strtok(c, " ");
str = strtok(NULL, " ");
x.word1 = (char *)malloc(sizeof(char) * (strlen(str) + 1));
strcpy(x.word1, str);
str = strtok(NULL, " ");
x.word2 = (char *)malloc(sizeof(char) * (strlen(str) + 1)); /* where the error happens with this input */
strcpy(x.word2, str);
str = strtok(NULL, "\0");
x.word3 = (char *)malloc(sizeof(char) * (strlen(str) + 1));
strcpy(x.word3, str);
temp->cont = x;
temp->next = head;
head = temp;
}
int main() {
char input[MAXINPUT] = " ";
head = NULL;
while (input[0] != 'x') {
fgets(input, MAXINPUT, stdin);
input[strcspn(input, "\r\n")] = 0;
if (input[0] == 'a')
add(input);
...
When I run this input with this code I get a Segmentation Error and valgrind says that there are 3 allocs and only one free and and that the leak\error happens in the line mentioned in the code, specifically with the strlen. It also says I can't access the memory position 0x0 for some reason. I wanted to know why this happens, Thanks!
You do not test if strtok did find all the tokens. You must check the pointer returned by strtok() before using it. If you don't, invalid input will cause undefined behavior.
In your case, the input is longer than 682 bytes, the first 681 bytes are read into the array and this fragment does not contain enough tokens, making one of the strtok() calls to return NULL, causing undefined behavior when you dereference this null pointer with strlen().
Always test and report error conditions, you will save yourself countless hours of debugging time.
When the program crashes, the memory leaks reported by valgrind are meaningless because the program did not complete its normal execution and of course did not free allocated memory properly. The memory is still returned to the operating system after program exit, but valgrind reports the blocks that have not been freed by calling free().
To avoid setting an arbitrary limit to the line length, you can use the POSIX standard function getline() that re-allocates the array as needed.
You should also use strdup to allocate copies of the strings in a single function call:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct words {
char *word1;
char *word2;
char *word3;
} words;
typedef struct node{
words cont;
struct node *next;
} node;
typedef node *link; // hiding pointers behind typedefs is not recommended
link head;
link add(char c[]) {
words x = { NULL, NULL, NULL };
char *str;
link temp;
if (strtok(c, " ") != NULL
&& (str = strtok(NULL, " ")) != NULL
&& (x.word1 = strdup(str)) != NULL
&& (str = strtok(NULL, " ")) != NULL
&& (x.word2 = strdup(str)) != NULL
&& (str = strtok(NULL, "")) != NULL
&& (x.word3 = strdup(str)) != NULL
&& (temp = malloc(sizeof(*temp)) != NULL) {
temp->cont = x;
temp->next = head;
return head = temp;
} else {
free(x.word3);
free(x.word2);
free(x.word1);
return NULL;
}
}
int main() {
char *input = NULL;
size_t input_size = 0;
head = NULL;
while (getline(&input, &input_size, stdin) >= 0 && *input != 'x') {
input[strcspn(input, "\r\n")] = '\0';
if (*input == 'a')
add(input);
...
}
...
}
free(input);
...
return 0;
}
Edited question:
Hi guys, my goal is to print the top 10 occurring words in a file, I have managed to get everything to work from reading the file to counting word occurrences and printing it, but when I implement my qsort I get a segfault. I looked over my pointers and they look okay to me, I would appreciate any feedback.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h>
#define MAX 51
struct words
{
char *ch;
int index;
struct words *pNext;
};
struct words* createWordCounter(char *ch)
{
struct words *pCounter = NULL;
pCounter = (struct words*)malloc(sizeof(char));
pCounter->ch = (char*)malloc(strlen(ch)+1);
strcpy(pCounter->ch, ch);
pCounter->index = 1;
pCounter->pNext = NULL;
return pCounter;
}
struct words *pStart = NULL;
char* removePunc(struct words* ch)
{
char *src = ch, *dst = ch;
while (*src)
{
if (ispunct((unsigned char)*src))
{
src++;
}
else if (isupper((unsigned char)*src))
{
*dst++ = tolower((unsigned char)*src);
src++;
}
else if (src == dst)
{
src++;
dst++;
}
else
{
*dst++ = *src++;
}
}
*dst = 0;
}
void addWord(char *word)
{
struct words *pCounter = NULL;
struct words *pLast = NULL;
if(pStart == NULL)
{
pStart = createWordCounter(word);
return;
}
pCounter = pStart;
while(pCounter != NULL)
{
if(strcmp(word, pCounter->ch) == 0)
{
++pCounter->index;
return;
}
pLast = pCounter;
pCounter = pCounter->pNext;
}
pLast->pNext = createWordCounter(word);
}
void printWord(struct words *pCounter)
{
printf("\n%-30s %5d\n", pCounter->ch, pCounter->index);
}
//sort
int compare (const void * a, const void * b){
struct words *A1 = (struct words *)a;
struct words *B1 = (struct words *)b;
return B1->index - A1->index;
/*
if ((A1->count - B1->count) > 0)
return -1;
else if ((A1->count - B2->count) < 0)
return 1;
else
return 0;
*/
}
int main(int argc, char * argv[])
{
struct words *pCounter = NULL;
char temp[MAX];
FILE *fpt;
if(argc == 2)
{
printf("File name is: %s\n",argv[1]);
fpt = fopen(argv[1], "r");
//fail test
if(fpt == NULL)
{
printf("cannot open file, exiting program...\n");
exit(0);
}
//get the data out of the file and insert in struct
int wordCounter = 0;
int i = 0;
int lines = 0;
while((fscanf(fpt, "%s ", &temp)) == 1)
{
removePunc(temp);
addWord(temp);
if(temp == ' ')
i++;
if(temp == '\n')
lines++;
wordCounter++;
}
/*
pCounter = pStart;
while(pCounter != NULL)
{
printWord(pCounter);
pCounter = pCounter->pNext;
}
*/
//sort
qsort(pCounter, wordCounter, sizeof(struct words), compare);
for(int j = 0; i < 10; i++)
{
printWord(pCounter);
}
}
fclose(fpt);
return 0;
}
First temp is already a pointer, so do not include '&' before it in fscanf. Second, don't skimp on buffer size (e.g. #define MAX 1024). Third, protect your array bounds with the field-width modifier and don't put trailing whitespace in your format-string.
Putting it altogether (presuming you use 1024 as MAX, you can use
fscanf(fpt, "1023%s", temp))
Well done on checking the return of fscanf during your read.
Adding to the things that have already been mentioned.
In createWordCounter(...)
pCounter = (struct words*)malloc(sizeof(char));
you are allocating memory for a char. Even though the pointer to a struct is the pointer to its first member, the first element of words is a pointer to a char. It is better to be careful and write
struct words *pCounter = malloc(sizeof *pCounter);
Also, be mindful of operator precedence.
In addWord(...) you have
++pCounter->index;
What that does is increment the pointer pCounter before accessing index. If you are trying to increment index, it should be
++(pCounter->index);
or
pCounter->index++;
I recommend striping your program down to its bare essentials and test each part one at a time systematically to narrow down the cause of your errors.
I think the main problem is the size of temp array when you try to using fscanf.
while((fscanf(fpt, "%s ", temp)) == 1)
When the length of one line is bigger than MAX, segmentation fault occur.
You can change your code like this
#define SCANF_LEN2(x) #x
#define SCANF_LEN(x) SCANF_LEN2(x)
//...
//your original code
//...
while((fscanf(fpt, "%"SCANF_LEN(MAX)"s ", temp)) == 1)
By the way, you should check
(1) compile warning about type
char* removePunc(struct words* ch)
should be char* removePunc(char *ch)
if(temp == ' ') should be if(temp[0] == ' ')
if(temp == '\n') should be if(temp[0] == '\n')
(2) malloc size
pCounter = (struct words*)malloc(sizeof(char)); should be pCounter = (struct words*)malloc(sizeof(struct words));
(3) remember free after using malloc
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.
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;
}
}