so i have a code that a little bit confused, so i build a struct :
typedef struct{
char *team_name;
}Team;
and other struct :
typedef struct{
Team** teams;
int num_teams;
}League;
and a function that create the struct Team:
Team* TeamCreate(char* team_n)
{
Team* t=(Team*)malloc(sizeof(Team));
t->team_name =team_n;
return t;
}
also for League struct:
League* LeagueCreate()
{
League* l=(League*)malloc(sizeof(League));
return l;
}
and the worst part is this function that should insert a words of text file into 'Team** teams'
so in every value of teams there is Team value that contain this word as char *team_name.
and the function make all teams list value equal to the last value of teams list.
the function:
void read_teams(League* l,char* text)
{
FILE *fp=fopen(text,"r");
char* tname=NULL;
size_t tname_size=0;
l->num_teams=0;
l->teams=NULL;
while(getline(&tname,&tname_size,fp)!=EOF)
{
char *p= strchr(tname,'\n');
if (p)
tname[p-tname]='\0';
l->teams=(Team**)realloc(l->teams,sizeof(Team*)*(l->num_teams+1));
l->teams[l->num_teams]=TeamCreate(tname);
l->num_teams++;
}
fclose(fp);
}
so for example my text file is :
Napoli
Salzburg
Liverpool
Genk
and when i write :
printf("\n%s\n",l->teams[0]->team_name);
printf("\n%s\n",l->teams[1]->team_name);
printf("\n%s\n",l->teams[2]->team_name);
printf("\n%s\n",l->teams[3]->team_name);
it print this:
Genk
Genk
Genk
Genk
and thanks for your time :).
The first time you call getline, sufficient space to hold the line will be allocated for you. Unless subsequent calls realloc the memory, you're passing the same exact pointer TeamCreate every time. Therefore, all of your Teams have the same char* and therefore the same team_name. Every time you update the string via getline, all of the team_names will change since they reference the same string.
What you need to do in TeamCreate is use the strdup function from string.h so that each Team gets its own string. I.e.,
t->team_name = strdup(team_n);
Read a .txt file line by line.
#define MAXCHAR 1000
char* filename = "G:\\test.txt";
fp = fopen(filename, "r");
if (fp == NULL){
printf("Could not open file %s",filename);
return 1;
}
while (fgets(str, MAXCHAR, fp) != NULL)
printf("%s", str);
fclose(fp);
Related
I would really appreciate help with this piece of code.
So I have defined a structure, and then an array of structures:
#define MAX_ITEMS 30
struct item{
char itemName[30];
int identification;
float sale;
};
struct item itemArray[MAX_ITEMS];
Then I have a function which takes the index of the array structure and is supposed to delete that element, and update the new array without the deleted element to the local .txt file
printf("item's index please: ");
char input[30];
gets(input);
for (int i=input; i<MAX_ITEMS;i++){
itemArray[i] = itemArray[i + 1];
}
FILE *fp
fp = fopen ("file.txt", "w");
int index = 0;
while(itemArray[index].itemName != ""){
fprintf(fp,"%s\n",itemArray[index].itemName);
fprintf(fp,"%d\n",itemArray[index].identification);
fprintf(fp,"%.2f\n",itemArray[index].sale);
index++;
}
fclose(fp);
So what I am expecting:
Instead, I get
Finishing after thousands of lines, like this:
I would appreciate any help!
I've got a problem regarding Dynamical Allocation & Structs.
The task: I have a struct of students, which looks like that:
typedef struct{
unsigned id;
char *lastName;
float grade;
}students_t;
I'm not allowed to pass to lastName a maximum number of characters, it must remain a pointer which size I will increase every time.
My code looks like this:
unsigned counter = 0;
students_t* students = NULL;
students_t temp;
char char_current;
unsigned char_counter=0;
while (fscanf(inputFile,"%u",&temp.id) == 1) {
students = realloc(students,(counter+1) * sizeof(students_t));
students[counter].id=temp.id;
printf("%d",students[counter].id);
students[counter].lastName = NULL;
while (fscanf(inputFile,"%c",&char_current) != ' ') {
students[counter].lastName = realloc(students[counter].lastName,(char_counter+1) * sizeof(char));
students[counter].lastName[char_counter] = char_current;
char_counter++;
}
students[counter].lastName[char_counter] = '\0';
fscanf(inputFile,"%f",&students[counter].grade);
counter++;
}
My problem is with the fscanf from the while (because the program enters an infinite loop), but I don't know how to actually fix it.
I would be grateful if someone could help me figure it out.
Thank you!
You have several problems:
The while() loop isn't terminating (your initial question).
fscanf() is unsafe - there are better alternatives.
You're using fscanf() incorrectly.
Reading a string a character at a time is inefficient.
Repeatedly calling "realloc()" is inefficient - there are better alternatives.
Here is some example code.
#include <stdio.h>
#include <malloc.h>
#include <string.h>
#define MAX_STRING 80
typedef struct {
unsigned id;
char *lastName;
float grade;
} students_t;
students_t* enter_new_student (FILE *inputFile)
{
char buffer[MAX_STRING];
unsigned id;
int iret;
// Check for end of input
iret = fscanf(inputFile, "%u", &id);
if ((iret < 1) || feof(inputFile)) { // iret should be "1" if successful
return NULL;
}
// Allocate a record and read its data
students_t *student = (students_t *)malloc(sizeof(students_t));
iret = fscanf(inputFile, "%s %f", buffer, &student->grade); // iret should be "2" if successful
student->id = id;
student->lastName = strdup(buffer); // strdup() does an implicit "malloc()" and "strcpy()"
// Return new student
return student;
}
int main()
{
students_t *student = NULL;
int record_counter = 0;
FILE *fp;
// Open file
if (!(fp = fopen("tmp.txt", "r"))) {
perror("unable to open file");
return 1;
}
// Read student records
while ((student = enter_new_student(fp))) {
if (student) {
++record_counter;
printf("new student=%s,id=%u, grade=%f, record_counter=%d\n",
student->lastName, student->id, student->grade, record_counter);
}
}
// Done
printf("Done: final record count=%d\n", record_counter);
return 0;
}
Here is a sample "tmp.txt" file:
1 Johnson 4.0
2 Jackson 3.5
3 Jamison 3.85
And corresponding sample output:
new student=Johnson,id=1, grade=4.000000, record_counter=1
new student=Jackson,id=2, grade=3.500000, record_counter=2
new student=Jamison,id=3, grade=3.850000, record_counter=3
In general, prefer using fgets() over fscanf(): Disadvantages of scanf
Notice that I put everything having to do with reading a student record inside a separate function: enter_new_student(). You'll also notice that the "control structure" - the "while loop" is OUTSIDE of the function.
There are two (related) conditions that can cause the loop to exit:
Didn't read "id"
End of file
The reason your original "while loop" failed was that fscanf() will never return ' ' ... so you inadvertently coded an "infinite loop". Here's why:
https://linux.die.net/man/3/fscanf
Return Value
These functions return the number of input items successfully matched and assigned, which can be fewer than provided
for, or even zero in the event of an early matching failure.
The value EOF is returned if the end of input is reached before either
the first successful conversion or a matching failure occurs. EOF is
also returned if a read error occurs, in which case the error
indicator for the stream (see ferror(3)) is set, and errno is set
indicate the error.
I am trying to assign element hash table[TABLE_SIZE] with input text file. So I used strcpy function. But it didn't copy into the array.
I've tried malloc to make the array in order to write in it. But it didn't work so I made a element* type variable pointing the hash_table array.But still didn't work.
//this is the header file
typedef struct {
char key[100];
char data[100];
} element;
element hash_table[TABLE_SIZE];
// For caomparison count
int num_comparison;
// 파일에서 단어들을 읽어 해시테이블 구성
int build_dictionary(char *fname);
int build_dictionary(char *fname) {
int i = 0; // num of data
char key[100], data[200];
FILE *ifp;
//pointing to the hash_table array
element* hash_table_p = hash_table;
hash_table_p = (element*)malloc(sizeof(element));
//file opening error
if ((ifp = fopen(fname, "r")) == NULL) {
printf("No such file ! \n");
exit(1);
}
while (fscanf(ifp, "%s %s", key, data) == 2) {
// (key data) assigning to array
//i've tried this because hash_table[i].data didn't work
strcpy(hash_table_p->data, data);
strcpy(hash_table_p->key, key);
strcpy(hash_table[i].data, hash_table_p->data);
strcpy(hash_table[i].key, hash_table_p->key);
i++;
//checking if it is well done
printf(" %s %s \n", hash_table_p->key, hash_table_p->data);
printf(" %d %s %s \n",i , hash_table[i].data, hash_table[i].key );
}
fclose(ifp);
return(i);
}
//the input text file went as below
one 하나
two 둘
three 셋
four 넷
five 다섯
When i executed the build_dictionary function, only one with the hash_table_p strcpy was assigned well and the hash_table had nothing in it.
element* hash_table_p = hash_table;
hash_table_p = (element*)malloc(sizeof(element));
You are overwritting the first assignment (getting new room for hash_table_p when you call malloc), as far as I can see you already define the size for the table, so you don't need to reserve more space (delete the line with malloc) and just increment the position of the pointer on each iteration (as you are already doing).
The program should read a simple text file and store the data ( name and id) into a linked list.
This is the linked list:
struct Prova
{
char nome[16];
int id;
};
typedef struct Node {
struct Prova struttura;
struct Node * next;
}TNodo;
typedef TNodo* Nodo;
This function creates the linked list:
void NewList(struct Prova p, Nodo * pp)
{
Nodo temp;
temp = (Nodo)malloc(sizeof(struct Node));
temp->struttura = p;
temp->next = *pp;
*pp = temp;
}
This is the function i wrote to read the file:
void Load(Nodo *pp)
{
FILE *f;
struct Prova p;
char * buffer;
if(!(f = fopen(PATH, "r")))
{
perror("Error");
exit(-1);
}
buffer = malloc(sizeof(struct Prova));
while(fgets(buffer, sizeof(buffer), f))
{
if(sscanf(buffer, "%s%d", p.nome, &p.id) > 0)
{
NewList(p, pp);
}
}
free(buffer);
fclose(f);
}
The text file i'm trying to read is this:
Stefano 31
Paperino 23
Pippo 1
Pluto 14
The functions for displaying the list are these:
void View(struct Prova p)
{
printf("%s %d\n", p.nome, p.id);
}
void ViewList(Nodo nodo)
{
while(nodo != NULL)
{
View(nodo->struttura);
nodo = nodo->next;
}
The program compiles fine, but it outputs the data in a strange order.
Let me know if you need more info, i think it's all related to the function Load() which is the newest.
Main function is this:
int main()
{
int scelta;
struct Prova test;
Nodo lista = NULL;
do {
scelta = Menu();
switch (scelta)
{
case 1: Load(&lista); break
case 2: ViewList(lista); break;
default: scelta = 0;
}
} while (scelta != 0);
return 0;
}
For now the output is this:
The problem is occurring because of passing sizeof(buffer) to fgets(). buffer is a pointer and sizeof(buffer) will return either 4 or 8 based on underlying architecture 32 bit or 64 bit. Change this to:
while(fgets(buffer, sizeof(struct Prova), f))
as you are allocating sizeof(struct Prova) size to buffer.
This is also not the correct solution of the problem. Reason is-
Say, your file is having this data:
abcdefghijklmno 123456789
The name part is 15 character long which nome member can hold and id member can also hold the number 123456789 as it is less than INT_MAX. fgets read characters from the stream and the size of above-given data is 25 characters. In your code, you are allocating sizeof(struct Prova) size memory to buffer and size of struct Prova is 20 byte. Hence for the above-given data, buffer is not allocated enough memory to read the whole line in one go because the fgets reads until size-1 characters have been read or either a newline or the end-of-file is reached, whichever happens first. So, in this case, the partial line will be read and passed to sscanf() and rest of the line will be read in next iteration and passed to sscanf() which will give the incorrect results.
You should not allocate the memory to buffer based on the size of struct Prova. Instead, I would suggest taking buffer of some bigger size, like this (no need to allocate it dynamically):
char buffer[100];
ensure it should be bigger enough to accommodate a line of the file in one read of fgets or modify your code to not to fill p.nome and p.id until fgets hits newline character or EOF i.e. to make sure to read the whole line and then only sscanf() the p.nome and p.id.
I have a text file and each line contains person name and gender in comma separated value. I am trying to read line by line and create the array of person. Not sure what went wrong with my code all the elements of the array is set to the last line of text file. (If the last line has Sam, Male, all the elements of the person array is set to Name=Sam)
struct Person{
char* Name;
char* Gender;
};
struct Person person[100];
void readAllFromFile(){
FILE * fp;
char currentLine[256];
int fd;
if((fp = fopen ("test.txt", "r"))==NULL){
perror("Can not open");
fclose(fp);
return;
}
int currentLineNo=0;
char *items;
while (fgets(currentLine, sizeof(currentLine), fp)) {
items=strtok(currentLine,",");
struct Person tempPerson;
int iter=0;
while(items != NULL)
{
if(iter==0){
tempPerson.Name=items;
}
else {
tempPerson.Gender=items;
}
iter++;
items=strtok(NULL,",");
}
person[currentLineNo]=tempPerson;
currentLineNo++;
}
/*Printing element of the array*/
int i;
for(i=0;i<currentLineNo;i++){
printf("%s\n",person[i].Name);
}
fclose(fp);
}
int main() {
readAllFromFile();
return 0;
}
The name of each person is located in the same place in memory: currentLine. You assign that address to every Persons Name, so every name will be displayed the same. Similar thing for each Gender.
Note that, because currentLine is local to readAllFromFile, once that function returns, that space may be used for other things, trashing the one Name you managed to retain.
Each Person needs its own allocation of space for its Name and Gender.