C Saving Data from a Text File into an Array of Structures - c

I want to ask about file processing and struct in C language. I am given an assignment where I need to have a .txt file containing: the names of basketball teams, the games they have played in total, the amount of games they have won, etc..
Here is the task:
Get data from user-specified .txt file (eg "data.txt")
Store the data in array of struct
Let the user have the ability to sort by name or the total amount of wins they have.
Here is an example, "data.txt" file:
Structure : name, games played, won at home, lost at home, won away, lost away
Fenerbahce-Dogus 25 12 0 10 3
Tofas 25 11 2 9 3
Anadolu-Efe 26 13 1 6 6
Banvit 26 9 4 8 5
Darussafaka 26 11 2 4 9
So far, I have been trying to allocate a dynamic array (of struct) and save the data from the txt file into said array. However, the program stops responding immediately whenever I try to enter the said "data.txt". as input. Could anybody inform me why this is happening and what should I do to get past this error?
Here is the code:
#include <stdio.h>
#include <stdlib.h>
typedef struct {
char *name;
int games;
int winsHome, losesHome;
int winsAway, losesAway;
int winsTotal, losesTotal;
int totalPoints;
} scoreboard;
void Load_Scoreboard_Table(char *, scoreboard *);
int main(){
char fileName[40];
FILE *inputFile;
while (1){
printf("Enter the file name> ");
gets(fileName);
inputFile = fopen(fileName,"r");
if (inputFile != NULL){
break;
}
printf("ERROR: The file %s could not be opened.\n",fileName);
printf("Please verify that the file exists.\n");
}
int listLength=0;
char curChar;
while ((curChar=fgetc(inputFile))!=EOF){
if (curChar=='\n'){
listLength++;
}
}
fclose(inputFile);
scoreboard *scoreboard_table = (scoreboard *)malloc(sizeof(scoreboard) * listLength);
Load_Scoreboard_Table(fileName,scoreboard_table);
return 0;
}
void Load_Scoreboard_Table(char *fileName,scoreboard *scoreboard_table){
FILE *inputFile;
fopen(fileName,"r");
int i=0;
while (fscanf(inputFile, "%s %d %d %d %d %d\n", (scoreboard_table+i)->name,(scoreboard_table+i)->games,(scoreboard_table+i)->winsHome,(scoreboard_table+i)->losesHome,(scoreboard_table+i)->winsAway,(scoreboard_table+i)->losesAway)!=EOF){
(scoreboard_table+i)->winsTotal = (scoreboard_table+i)->winsHome + (scoreboard_table+i)->winsAway;
(scoreboard_table+i)->losesTotal = (scoreboard_table+i)->losesHome + (scoreboard_table+i)->losesAway;
(scoreboard_table+i)->totalPoints = (((scoreboard_table+i)->winsTotal)*2) + (scoreboard_table+i)->losesTotal;
i++;
}
}
Update:
I have managed to read from the file and save it in struct array.(Also added a print function). However I still cannot get it to stop freezing once it finishes printing the function (it would freeze after saving data into the array before).
Note: I know many people have warned me not to use gets; but, my teacher told me to use it for now.
Note2: I decided to have a static char name inside the struct
Note3: I have only learned about data structures today, so I'm VERY new to the topic; therefore, please explain things without going into too much detail.
What could be causing the code below to freeze?
Code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct { // defining a struct here
char name[40]; // name of the sports club
//clubs containing multiple words should be written in the following format: 'name-name-name'
//ex : 'Anadolu Efe' should be written as 'Anadolu-Efe' in the text file
//This is to avoid confusion when reading from .txt file
int games;
int winsHome, losesHome;
int winsAway, losesAway;
int winsTotal, losesTotal;
int totalPoints;
} scoreboard;
void Load_Scoreboard_Table(char *, scoreboard *); // reads the .txt file and saves the contents into scoreboard_table
void Display_Scoreboard_Table(scoreboard *, int); // displays scoreboard_table, also takes it's size as input
int main(void){
char fileName[40]; // the name of the file will be stored here (ex: data.txt)
FILE *inputFile; // creating a stream to read from .txt file
while (1){ // Ask user for the name of the file until said file is opened for reading
printf("Enter the file name> ");
gets(fileName); // get string input from user that supports space characters (eg: "data.txt")
inputFile = fopen(fileName,"r"); // try opening file in read mode
if (inputFile != NULL){ //if the file has succesfully opened, then break from the loop
break;
}
printf("ERROR: The file %s could not be opened.\n",fileName); //if the file was not succesfully opened, then print appropriate error message
printf("Please verify that the file exists.\n");
}
int listLength=0; //will be used to dynamically allocate memory for scoreboard_table array (array of structs)
int curChar; // I figured that fgetc returns an integer value
while ((curChar=fgetc(inputFile))!=EOF){ //get a character until EOF
if (curChar=='\n'){ //if it's a newline character then we need to allocate more memory for scoreboard_table array
listLength++;
}
}
fclose(inputFile); // close the file as it's job is done
scoreboard *scoreboard_table = malloc(sizeof(scoreboard) * listLength); // allocating enough memory to store the contents of .txt file
Load_Scoreboard_Table(fileName,scoreboard_table); //save the contents of file on scoreboard_table
while (1){
Display_Scoreboard_Table(scoreboard_table,listLength);
break;
}
free(scoreboard_table); //freeing memory allocated for scoreboard_table
return 0;
}
void Load_Scoreboard_Table(char *fileName,scoreboard *scoreboard_table){
FILE *inputFile = fopen(fileName,"r"); // creating stream to read from file
if(inputFile == NULL ) { //checking again just in case there is a problem opening the file
printf("ERROR: The file %s could not be opened.\n",fileName);
exit(1);
}
int i=0,j,k;
//the loop below gets data from .txt file line by line until EOF and stores it in scoreboard_table array
while (fscanf(inputFile,"%s %d %d %d %d %d", (scoreboard_table+i)->name,&(scoreboard_table+i)->games,&(scoreboard_table+i)->winsHome,&(scoreboard_table+i)->losesHome,&(scoreboard_table+i)->winsAway,&(scoreboard_table+i)->losesAway) != EOF){
(scoreboard_table+i)->winsTotal = (scoreboard_table+i)->winsHome + (scoreboard_table+i)->winsAway;
(scoreboard_table+i)->losesTotal = (scoreboard_table+i)->losesHome + (scoreboard_table+i)->losesAway;
(scoreboard_table+i)->totalPoints = (((scoreboard_table+i)->winsTotal)*2) + (scoreboard_table+i)->losesTotal;
i++;
}
//the loop below replaces the '-' characters with ' ' in the name of every scoreboard_table array
for (j=0;j<i;j++){
for (k=0;k<40;k++){
if ((scoreboard_table+i)->name[k] == '-'){
(scoreboard_table+i)->name[k] = ' ';
}
}
}
printf("Score records file has been successfully loaded!\n");
}
void Display_Scoreboard_Table(scoreboard *scoreboard_table,int size){
printf("Team G WH LH WA LA Won Lost Points\n");
int i;
for (i=0;i<=size;i++){
printf("%-40s%5d %5d %5d %5d %5d %5d %5d %5d\n",(scoreboard_table+i)->name,(scoreboard_table+i)->games,(scoreboard_table+i)->winsHome,(scoreboard_table+i)->losesHome,(scoreboard_table+i)->winsAway,(scoreboard_table+i)->losesAway,(scoreboard_table+i)->winsTotal,(scoreboard_table+i)->losesTotal,(scoreboard_table+i)->totalPoints);
}
}
Thank you.
Update 2 (With working code):
The issue was caused by me allocating wrong amount of memory for the array of structs called scoreboard_table. To be more specific, I was allocating memory for array that could hold 1 less line than the file.
I have updated the code again. It is working now... (For the most part, except when an unexpected input is entered(such as being fed an empty file, or user entering more characters into gets).)
This code is more than enough for my assignment as my teachers have not asked for a more detailed program(infact, they do get angry if we submit more complicated programs since we have not yet learnt about them in class - which is why I'm using gets() and not fgets() for example).
However I'm curious to hear your opinions on the matter. What do you think I should do to improve this?
By the way, I am aware of the grammar-spelling mistakes in the code. It's just because we need to strictly obey the input-output format in our assignments and typing things differently means losing points.
Code:
/* -*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-
~ ~ ~ ~ VERY IMPORTANT ~ ~ ~ ~
The text file containing the data should be written in the following format:
"%s %d %d %d %d %d\n" where
%s is the name of the club
If the name of the club contains more than one word, it should be written without any space characters ' '; instead place dash characters '-'
Example: 'Anadolu Efe' should be written as 'Anadolu-Efe' in the text file
complete line example:
"Anadolu-Efe 26 13 1 6 6"
-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*- */
//including required libraries
#include <stdio.h>
#include <stdlib.h> //used to dynamically allocate memory
#include <string.h> //used for some string manipulation functions
typedef struct { // defining a struct here
char name[40]; // name of the sports club
//clubs containing multiple words should be written in the following format: 'name-name-name'
//ex : 'Anadolu Efe' should be written as 'Anadolu-Efe' in the text file
//This is to avoid confusion when reading from .txt file
int games;
int winsHome, losesHome;
int winsAway, losesAway;
int winsTotal, losesTotal;
int totalPoints;
} scoreboard;
void Load_Scoreboard_Table(char *, scoreboard *); // reads the .txt file and saves the contents into scoreboard_table
void Display_Scoreboard_Table(scoreboard *, int); // displays scoreboard_table, also takes it's size as input
void Search(scoreboard *, int, char *); // searches if a team exists in the scoreboard array and if there is; it prints the stats of the team
void interactive_board(scoreboard *, int, int); // sorts the scoreboard array depending on user input, (sort by: games, points)
/*
This program reads data from a txt data, stores it in an array of structs
The program has the ability to sort the array based on either points or games
It also can search for the name inside said array of structs
*/
int main(){
char fileName[40]; // the name of the file will be stored here (ex: data.txt)
char searchTerm[40]; // search term will be stored here
FILE *inputFile; // creating a stream to read from .txt file
int i; // will be used later in a loop
while (1){ // Ask user for the name of the file until said file is opened for reading
printf("Enter the file name: ");
gets(fileName); // get string input from user that supports space characters (eg: "data.txt")
inputFile = fopen(fileName,"r"); // try opening file in read mode
if (inputFile != NULL){ //if the file has succesfully opened, then break from the loop
break;
}
printf("ERROR: The file %s could not be opened.\n",fileName); //if the file was not succesfully opened, then print appropriate error message
printf("Please verify that the file exists.\n");
}
int listLength=1; //will be used to dynamically allocate memory for scoreboard_table array (array of structs)
int curChar; // I figured that fgetc returns an integer value
while ((curChar=fgetc(inputFile))!=EOF){ //get a character until EOF
if (curChar=='\n'){ //if it's a newline character then we need to allocate more memory for scoreboard_table array
listLength++;
}
}
fclose(inputFile); // close the file as it's job is done
scoreboard *scoreboard_table = malloc(sizeof(scoreboard) * (listLength)); // allocating enough memory to store the contents of .txt file
if (scoreboard_table == NULL){
printf("ERROR: There has been an error allocating memory for scoreboard table array.\n");
exit(1);
}
Load_Scoreboard_Table(fileName,scoreboard_table); //save the contents of file on scoreboard_table
Display_Scoreboard_Table(scoreboard_table,listLength);
while (1){
printf("Enter the name of the team (Exit - X, Sort -S): ");
gets(searchTerm);
i=0;
while (searchTerm[i]!='\0'){
searchTerm[i]=toupper(searchTerm[i]);
i++;
}
if (strcmp(searchTerm,"X")==0){
printf("Bye!\n");
free(scoreboard_table); //freeing memory allocated for scoreboard_table
return 0;
}
else if (strcmp(searchTerm,"S")==0){
printf("Sort by (G: games, P: points): ");
gets(searchTerm);
i=0;
while (searchTerm[i]!='\0'){
searchTerm[i]=toupper(searchTerm[i]);
i++;
}
if (strcmp(searchTerm,"G")==0){
interactive_board(scoreboard_table,listLength,1);
Display_Scoreboard_Table(scoreboard_table,listLength);
}
else if (strcmp(searchTerm,"P")==0){
interactive_board(scoreboard_table,listLength,2);
Display_Scoreboard_Table(scoreboard_table,listLength);
}
else{
printf("ERROR: Invalid input. There is no sort term for '%s'\n",searchTerm);
}
}
else{
Search(scoreboard_table,listLength,searchTerm);
}
}
}
void Load_Scoreboard_Table(char *fileName,scoreboard *scoreboard_table){
FILE *inputFile = fopen(fileName,"r"); // creating stream to read from file
if(inputFile == NULL ) { //checking again just in case there is a problem opening the file
printf("ERROR: The file %s could not be opened.\n",fileName);
exit(1);
}
int i=0,j,k;
//the loop below gets data from .txt file line by line until EOF and stores it in scoreboard_table array
while (fscanf(inputFile,"%s %d %d %d %d %d", (scoreboard_table+i)->name,&(scoreboard_table+i)->games,&(scoreboard_table+i)->winsHome,&(scoreboard_table+i)->losesHome,&(scoreboard_table+i)->winsAway,&(scoreboard_table+i)->losesAway) != EOF){
(scoreboard_table+i)->winsTotal = (scoreboard_table+i)->winsHome + (scoreboard_table+i)->winsAway;
(scoreboard_table+i)->losesTotal = (scoreboard_table+i)->losesHome + (scoreboard_table+i)->losesAway;
(scoreboard_table+i)->totalPoints = (((scoreboard_table+i)->winsTotal)*2) + (scoreboard_table+i)->losesTotal;
i++;
}
//the loop below replaces the '-' characters with ' ' in the name of every scoreboard_table array
for (j=0;j<i;j++){
for (k=0;k<40;k++){
if (*(((*(scoreboard_table+j)).name)+k) == '-' ){ //if the value of name[k] inside scoreboard_table[j] is equal to '-' character
*(((*(scoreboard_table+j)).name)+k) = ' '; //replace the value of scoreboard_table[j].name[k] to ' ' character
}
}
}
fclose(inputFile); // close the file as it's job is done
printf("Score records file has been successfully loaded!\n"); // notify the user that reading from the file has been successful
}
void Display_Scoreboard_Table(scoreboard *scoreboard_table,int size){
printf("\nTeam G WH LH WA LA Won Lost Points\n\n"); // the variables to be shown in table
int i;
for (i=0;i<size;i++){//for every element in scoreboard_table, print the variables stored
printf("%-40s%5d %5d %5d %5d %5d %5d %5d %5d\n",(scoreboard_table+i)->name,(scoreboard_table+i)->games,(scoreboard_table+i)->winsHome,(scoreboard_table+i)->losesHome,(scoreboard_table+i)->winsAway,(scoreboard_table+i)->losesAway,(scoreboard_table+i)->winsTotal,(scoreboard_table+i)->losesTotal,(scoreboard_table+i)->totalPoints);
}
}
void Search(scoreboard *scoreboard_table, int size, char *searchTerm){ //search for name of team in scoreboard_table
int i,j; //i = index of scoreboard_table array, j = index of name array inside scoreboard_table array
char table_name[40]; // will be used to convert scoreboard_table->name to uppercase and store it
for (i=0;i<size;i++){ // for every element in scoreboard_table
for (j=0;j<40;j++){ // for every character in the name of scoreboard_table[i]->name
table_name[j]=toupper(*(((*(scoreboard_table+i)).name)+j)); //store the upper-case letter of scoreboard_table[i]->name[j] in table_name[j]
}
if (strcmp(table_name,searchTerm)==0){
//if the search term is equal to table_name (which is uppercase version of scoreboard_table[i]->name), then print the statistics and break from the loop.
printf("%s has %d win, %d lost and a total of %d points!\n",(scoreboard_table+i)->name,(scoreboard_table+i)->winsTotal,(scoreboard_table+i)->losesTotal,(scoreboard_table+i)->totalPoints);
break;
}
else if(i==(size-1)){
// if it's the last element of scoreboard_table array and the search term is not equal to scoreboard_table[i]->name
// notify the user that their search term is not found in the scoreboard_table array
printf("That team is unknown! Please try again!\n");
}
}
}
void interactive_board(scoreboard *scoreboard_table, int size, int sort){
//this function sorts the scoreboard_table array using selection sort algorithm
/*
selection sort algorithm sorts an array by repeatedly finding the maximum element from unsorted part and putting it at the beginning.
*/
int i,j,index;
/*
i is used in a for loop to get ith element of scoreboard_table
j is used to determine when the sorting is complete
(ie: if you have a list containing 5 elements, you need to sort the array 4 times at most(in this case, which is selection sort algorithm);
therefore j is used in a for loop : for (j=0;j<(sizeofArray-1);j++)
j is also used to write into jth element of scoreboard_table
*/
int max; //store the max value here
scoreboard temp; //declare a struct named temp, will store temporary data when swapping variables of scoreboard_table array
if (sort==1){ // if sorting based on games
for (j=0;j<size-1;j++){ // explained above, iterate the code below (array) size-1 times
max=(scoreboard_table+size-1)->games; //set max to the last element of the array since this is the unsorted part of array...
index=size-1; //set index to index of last element of the array...
for (i=j;i<size;i++){ //no need to search elements with index less than j since they are already sorted
//therefore start searching elements from j till the last element
if (max<((scoreboard_table+i)->games)){
//if the value of current element > max, then the max value becomes this value and the index of the new max value is stored in index
max=(scoreboard_table+i)->games;
index=i;
}
if (i==(size-1)){ // swap the variables of scoreboard_table[index] with the variables of scoreboard_table[j]
//where j stands for the next unsorted member and index stands for the index of the largest variable
//copy contents of scoreboard_table[j] into temp (BACKUP)
strcpy(temp.name,(scoreboard_table+j)->name);
temp.games=(scoreboard_table+j)->games;
temp.losesAway=(scoreboard_table+j)->losesAway;
temp.losesHome=(scoreboard_table+j)->losesHome;
temp.losesTotal=(scoreboard_table+j)->losesTotal;
temp.totalPoints=(scoreboard_table+j)->totalPoints;
temp.winsAway=(scoreboard_table+j)->winsAway;
temp.winsHome=(scoreboard_table+j)->winsHome;
temp.winsTotal=(scoreboard_table+j)->winsTotal;
//copy contents of scoreboard_table[index] into scoreboard_table[j]
strcpy((scoreboard_table+j)->name,(scoreboard_table+index)->name);
(scoreboard_table+j)->games=(scoreboard_table+index)->games;
(scoreboard_table+j)->losesAway=(scoreboard_table+index)->losesAway;
(scoreboard_table+j)->losesHome=(scoreboard_table+index)->losesHome;
(scoreboard_table+j)->losesTotal=(scoreboard_table+index)->losesTotal;
(scoreboard_table+j)->totalPoints=(scoreboard_table+index)->totalPoints;
(scoreboard_table+j)->winsAway=(scoreboard_table+index)->winsAway;
(scoreboard_table+j)->winsHome=(scoreboard_table+index)->winsHome;
(scoreboard_table+j)->winsTotal=(scoreboard_table+index)->winsTotal;
//copy contents of temp (BACKUP) into scoreboard_table[index]
strcpy((scoreboard_table+index)->name,temp.name);
(scoreboard_table+index)->games=temp.games;
(scoreboard_table+index)->losesAway=temp.losesAway;
(scoreboard_table+index)->losesHome=temp.losesHome;
(scoreboard_table+index)->losesTotal=temp.losesTotal;
(scoreboard_table+index)->totalPoints=temp.totalPoints;
(scoreboard_table+index)->winsAway=temp.winsAway;
(scoreboard_table+index)->winsHome=temp.winsHome;
(scoreboard_table+index)->winsTotal=temp.winsTotal;
}
}
}
}
else{ // if sorting based on points
for (j=0;j<size-1;j++){ // explained above, iterate the code below (array) size-1 times
max=(scoreboard_table+size-1)->totalPoints; //set max to the last element of the array since this is the unsorted part of array...
index=size-1; //set index to index of last element of the array...
for (i=j;i<size;i++){ //no need to search elements with index less than j since they are already sorted
//therefore start searching elements from j till the last element
if (max<((scoreboard_table+i)->totalPoints)){
//if the value of current element > max, then the max value becomes this value and the index of the new max value is stored in index
max=(scoreboard_table+i)->totalPoints;
index=i;
}
if (i==(size-1)){ // swap the variables of scoreboard_table[index] with the variables of scoreboard_table[j]
//where j stands for the next unsorted member and index stands for the index of the largest variable
//copy contents of scoreboard_table[j] into temp (BACKUP)
strcpy(temp.name,(scoreboard_table+j)->name);
temp.games=(scoreboard_table+j)->games;
temp.losesAway=(scoreboard_table+j)->losesAway;
temp.losesHome=(scoreboard_table+j)->losesHome;
temp.losesTotal=(scoreboard_table+j)->losesTotal;
temp.totalPoints=(scoreboard_table+j)->totalPoints;
temp.winsAway=(scoreboard_table+j)->winsAway;
temp.winsHome=(scoreboard_table+j)->winsHome;
temp.winsTotal=(scoreboard_table+j)->winsTotal;
//copy contents of scoreboard_table[index] into scoreboard_table[j]
strcpy((scoreboard_table+j)->name,(scoreboard_table+index)->name);
(scoreboard_table+j)->games=(scoreboard_table+index)->games;
(scoreboard_table+j)->losesAway=(scoreboard_table+index)->losesAway;
(scoreboard_table+j)->losesHome=(scoreboard_table+index)->losesHome;
(scoreboard_table+j)->losesTotal=(scoreboard_table+index)->losesTotal;
(scoreboard_table+j)->totalPoints=(scoreboard_table+index)->totalPoints;
(scoreboard_table+j)->winsAway=(scoreboard_table+index)->winsAway;
(scoreboard_table+j)->winsHome=(scoreboard_table+index)->winsHome;
(scoreboard_table+j)->winsTotal=(scoreboard_table+index)->winsTotal;
//copy contents of temp (BACKUP) into scoreboard_table[index]
strcpy((scoreboard_table+index)->name,temp.name);
(scoreboard_table+index)->games=temp.games;
(scoreboard_table+index)->losesAway=temp.losesAway;
(scoreboard_table+index)->losesHome=temp.losesHome;
(scoreboard_table+index)->losesTotal=temp.losesTotal;
(scoreboard_table+index)->totalPoints=temp.totalPoints;
(scoreboard_table+index)->winsAway=temp.winsAway;
(scoreboard_table+index)->winsHome=temp.winsHome;
(scoreboard_table+index)->winsTotal=temp.winsTotal;
}
}
}
}
}

you have lot of problems in your code like.
Firstly, use fgets() instead of gets(). for e.g
fgets(fileName,sizeof(fileName),stdin);
Secondly, name is pointer member of scoreboard, allocate memory for it first. for e.g
scoreboard_table->name = malloc(SIZE); /* define SIZE */
Thirdly, fgetc() return type is int. check the manual page of fgetc(). So char curChar; should be int curChar;
Finally, in fscanf() while storing integers you need to provide the & address to each argument. for e.g
fscanf(inputFile,"%d",&(scoreboard_table+i)->games)
I try to explain in the comments. Here is the sample code
void Load_Scoreboard_Table(char *, scoreboard *);
int main(void){
char fileName[40], *ret = NULL;
FILE *inputFile;
while (1){
printf("Enter the file name> ");
/* make sure fileName gets correctly stored in buffer as expected */
ret = fgets(fileName,sizeof(fileName),stdin); /* use fgets() instead of gets() */
if(ret == NULL) { /* if failed, check again */
continue;
}
else {
printf("%s",ret); /* if fgets() result is as expected, control comes here */
fileName[strlen(fileName)-1] ='\0';
}
inputFile = fopen(fileName,"r");
if (inputFile != NULL){
break;
}
printf("ERROR: The file %s could not be opened.\n",fileName);
printf("Please verify that the file exists.\n");
}
int listLength=0;
int curChar; /*return type of fgetc() is int */
while ((curChar=fgetc(inputFile))!=EOF){
if (curChar=='\n'){
listLength++;
}
}
fclose(inputFile);
scoreboard *scoreboard_table = malloc(sizeof(scoreboard) * listLength);/* no need to cast the result of malloc() */
scoreboard_table->name = malloc(100);/*name is pointer member, allocate memory for it. must */
Load_Scoreboard_Table(fileName,scoreboard_table);
/* don't forget to free dynamically allocated memory here #TODO */
return 0;
}
void Load_Scoreboard_Table(char *fileName,scoreboard *scoreboard_table){
FILE *inputFile = fopen(fileName,"r");
if(inputFile == NULL ) {
/* some mesage,, error handling #TODO*/
}
int i=0;
while (fscanf(inputFile,"%s %d %d %d %d %d", (scoreboard_table+i)->name,&(scoreboard_table+i)->games,&(scoreboard_table+i)->winsHome,&(scoreboard_table+i)->losesHome,&(scoreboard_table+i)->winsAway,&(scoreboard_table+i)->losesAway) > 0){
(scoreboard_table+i)->winsTotal = (scoreboard_table+i)->winsHome + (scoreboard_table+i)->winsAway;
(scoreboard_table+i)->losesTotal = (scoreboard_table+i)->losesHome + (scoreboard_table+i)->losesAway;
(scoreboard_table+i)->totalPoints = (((scoreboard_table+i)->winsTotal)*2) + (scoreboard_table+i)->losesTotal;
i++;
}
for(int j =0 ;j<i;j++) {
printf("%d %d %d \n",(scoreboard_table+j)->winsTotal,(scoreboard_table+j)->losesTotal,(scoreboard_table+j)->totalPoints);
}
}
From man 3 gets Why one shouldn't use gets() reason is here.
Never use gets(). Because it is impossible to tell without knowing
the data in advance how many characters gets() will read,
and because gets() will continue to store characters past the end of the buffer, it is extremely dangerous to use. It has
been used to break computer security. Use fgets() instead.

Pay special attention to contents of your fscanf(). Addresses of int variables have to be passed it's the one of crashing reason of the code.
while (fscanf(inputFile, "%s %d %d %d %d %d\n",
(scoreboard_table+i)->name, &(scoreboard_table+i)->games,
&(scoreboard_table+i)->winsHome, &(scoreboard_table+i)->losesHome,
&(scoreboard_table+i)->winsAway,&(scoreboard_table+i)->losesAway)!=EOF){
Moreover, you should give ear to the other comments like not using gets()
char fileName[40], *p;
fgets(fileName, sizeof fileName, stdin);
if ((p = strchr(fileName, '\n')) != NULL) {
*p = '\0'; /* remove newline */
}
By the way, an allocated memory is needed for char *name in the struct, it's the another reason for crashing, and not forget to free it.

Related

fscanf consumes first letter in file. How do I fix it?

I am making a program for a class that reads the contents of a .csv file. I am using a while loop inside of a for loop to scan the contents into two separate arrays, and when it prints the contents, everything is right, except it is missing the first letter in the file. We are not allowed to use any functions from the library except what is permitted.
Code in question:
void readFile(FILE *fptr, int size)
{
int i, a;
a = size / 2;
printf("number of lines in readFile is %d:\n", size);
double y[50];
char x[50];
for (i = 0; i < a; i++)
{
while (fscanf(fptr,"%c,%lf,", &x[i], &y[i]) ==2);
}
printf("%c, %.2lf: ", x[0], y[0]);
//a loop to make sure it scanned properly by displaying array contents
for (i = 0; i < a; i++)
{
printf("%c, %.2lf:\n", x[i], y[i]);
}
}
I tried with no luck to !feof(fptr), != EOF, but these are not supposed to be used in the intro class I am taking. I am out of ideas to fix it.
This is the output of the program above:
number of lines in readFile is 4:
, 20.00:
, 20.00:
E, 30.00:
number of lines is 4:
A few issues ...
The fscanf format is wrong. It needs a leading space to skip over newlines.
Unless you intend to operate on the data read in readFile (vs. passing it back to caller), having function scoped x and y arrays will go out of scope when the function returns.
The caller of readFile should pass the maximum array count but let the function determine the actual number of entries.
Whenever I see two or more "parallel" arrays [indexed by the same variable], I would use a struct. Particularly for .csv data.
.csv files are of the form: a,b\nc,d\n and not a,b,\nc,d,\n so the trailing , in the fscanf is incorrect.
Using nested loops for the data input doesn't work.
No need for feof. Just loop until the fscanf return is not 2.
Here is the corrected code. It is annotated:
#include <stdio.h>
#include <stdlib.h>
// data for single .csv line
struct data {
char x;
double y;
};
// readFile -- read in .csv file
// RETURNS: count of records/lines read
size_t
readFile(FILE *fptr, struct data *arr, size_t size)
// fptr -- open file stream
// arr -- pointer to data array
// size -- maximum number of elements in arr
{
int count = 0;
while (1) {
// check for overflow of array
if (count >= size) {
fprintf(stderr,"readFile: too much data for array\n");
exit(1);
}
// point to current struct/record
struct data *cur = &arr[count];
// read in the .csv line -- stop on error or EOF
if (fscanf(fptr, " %c,%lf", &cur->x, &cur->y) != 2)
break;
// advance the count of the number of valid elements
++count;
}
return count;
}
int
main(int argc,char **argv)
{
struct data arr[50];
// skip over program name
--argc;
++argv;
if (argc != 1) {
printf("wrong number of arguments\n");
exit(1);
}
// open the input file
FILE *fptr = fopen(argv[0],"r");
if (fptr == NULL) {
perror(argv[0]);
exit(1);
}
// read in the data lines
size_t count = readFile(fptr,arr,sizeof(arr) / sizeof(arr[0]));
fclose(fptr);
// print the array
for (size_t idx = 0; idx < count; ++idx) {
struct data *cur = &arr[idx];
printf("%c, %.2f:\n",cur->x,cur->y);
}
return 0;
}
Here is the sample input I used to test the program:
J,23
D,37.62
F,17.83
Here is the program output:
J, 23.00:
D, 37.62:
F, 17.83:

How to write arrays of integers to binary files?

Hello I am trying to write a program that stores two separate integer arrays and one float array, my code below does this but without the array part, in other words I can write a single digit to a file and print it back out, but I cannot find out how to do the exact same thing but with an array (Dynamically Allocated). Here is the code below: it takes three values (part number, quantity and price) and repeats taking the values in until the user enters 0 for part number (pn).
Then writes that data into a file called "inventory.txt", then in the same program, open the file for reading and display those values back on the terminal.
So far, the program can only handle one number in the variables at a time(duh), I just can't figure out how to do the same thing but with an array that gets bigger with each added element.
#include <stdio.h>
#include <stdlib.h>
int main(){
printf("This program stores an invetory: ");
int i=0, holdr, k; //declarations of needed variables
int pn, q;
float p;
FILE *fp;
fp=fopen("inventory.txt","w+b"); //open file
while(holdr!=0){ //aka while pn!=0, for some reason needed a separate variable to run loop coorectly
printf("Please enter item data (part number, quantity, price): ");
scanf("%d,%d,%f",*pn,*q,*p);//scan numbers into respective variables, need to turn these into ARRAYS
//pn = malloc((i+1) * sizeof(int)); (setting aside this part of code as I can't get it to work properly at all (for the dynamic aspect of the program(array increases in size as user enters more digits)))
//q = malloc((i+1) * sizeof(int));
//p = malloc((i+1) * sizeof(int));
fwrite(&pn,sizeof(int),1,fp); //write to file
fwrite(&q,sizeof(int),1,fp);
fwrite(&p,sizeof(int),1,fp);
holdr=pn; //set pn=holdr for the running loop
}
rewind(fp);//back to beginning of file
fp=fopen("inventory.txt","r+b"); //open for reading
if (fp == NULL){ //check for file
printf("nah");
exit(EXIT_FAILURE);
}
fread(&pn,sizeof(int),k,fp); //read and then print the values in the file stored in the specified variables, nned to turn these variables into ARRAYS
printf("%d\t" , **pn);
fread(&q,sizeof(int),k,fp);
printf("%d\t", **q);
fread(&p,sizeof(int),k,fp);
printf("%f\n", **p);
fclose(fp);//close file
return 0;}
Here is the second try I made, a lot closer, but it won't compile as the cast of malloc inside the while loop is incorrect and I have no idea what is the correct way to allocate the space through every iteration.
#include <stdio.h>
#include <stdlib.h>
int main(){
printf("This program stores an invetory: ");
int i=0, holdr, k;
int pn[1], q[1];
float p[1];
FILE *fp;
fp=fopen("inventory.txt","w+b");
while(holdr!=0){
printf("Please enter item data (part number, quantity, price): ");
scanf("%d,%d,%f",&pn[i],&q[i],&p[i]);
pn=malloc((i+1) * sizeof(int));
q=malloc((i+1) * sizeof(int));
p=malloc((i+1) * sizeof(float));
fwrite(&pn[i],sizeof(int),k+1,fp);
fwrite(&q[i],sizeof(int),k+1,fp);
fwrite(&p[i],sizeof(float),k+1,fp);
holdr=pn[i];
i++;
}
rewind(fp);
fp=fopen("inventory.txt","r+b");
if (fp == NULL){
printf("nah");
exit(EXIT_FAILURE);
}
fread(&pn,sizeof(int),k,fp);
printf("%d\t" , pn[2]);
fread(&q,sizeof(int),k,fp);
printf("%d\t", q[2]);
fread(&p,sizeof(int),k,fp);
printf("%f\n", p[2]);
fclose(fp);
return 0;}

Using qsort and strcmp prior to my sctrucs going into txt files

My code pulls data from one text file and then totals the points and enters it into a separate text file, so I would like the program to organize the teams and scores by total points prior to frpintf into the text file. So far the program pulls and runs the data and totals it out and fprintf just fine, should I use qsort to sort and print into the text file, and where in my code do I place it. Here is the text it is reading.
Indians 54 45 5
Twins 45 53 7
Tigers 43 59 8
White_Sox 35 64 9
Royals 30 69 3
Also I know there are no ties in the MLB lol just throwing in an additional variable.
Thanks.
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <string.h>
int main(void)
{
struct records {
char filename;
char team[50];
int wins;
int tie;
int loss;
int points;
};
struct records roster;
FILE *ifp = NULL;
FILE *afd = NULL;
const int argv;
char filename2[64] = {0};
char filename[64] = {0};
int points;
int points2;
int total;
printf("\nPlease enter the the .txt file you would like to open: ");
scanf("%63s", filename);
printf("Opened file name %s",filename);
ifp = fopen(filename,"r");
if (ifp == NULL)
{
printf("Could not open");
printf("\nPlease enter the the .txt file you would like to open:");
scanf("%63s", filename);
printf("Opened file name %s",filename);
ifp = fopen(filename,"r");
}
printf("\nReading the file %s \n", filename);
while(fscanf(ifp, "%s %d %d%d" , roster.team, &roster.wins, &roster.loss,
&roster.tie) != EOF)
printf("%s Wins:%d Losses:%d ties:%d\n", roster.team, roster.wins,
roster.loss, roster.tie);
printf("\nWins are worth 2 points ties are worth 1 point and losses are
worth \nzero in overall league standings.");
printf("\nHere are the overall ALCentral Standings!\n");
ifp = fopen(filename, "r");
fopen(filename, "r"); while(fscanf(ifp, "%s %d %d %d", roster.team,
&roster.wins, &roster.loss, &roster.tie) != EOF)
printf("%s Wins:%d Losses:%d ties:%d Total league points:%d\n",
roster.team, roster.wins, roster.loss, roster.tie, (roster.wins * 2 +
roster.tie * 1), total);
printf("closing %s", filename);
fclose(ifp);
printf("\nPlease enter the the .txt file you would like to write to: ");
scanf("%63s", filename2);
printf("Opened file name %s", filename2);
afd = fopen(filename2, "a+");
if (afd == NULL)
{
printf("Could not open"); printf("\nPlease enter the the .txt file you
would like to open: ");
scanf("%63s", filename2);
printf("Opened file name %s", filename2);
afd = fopen(filename2,"a+");
}
ifp = fopen(filename,"r");
fopen(filename, "r");
points = roster.wins * 2;
points2 = roster.tie * 1;
total = points + points2;
while(fscanf(ifp, "%s %d %d %d", roster.team, &roster.wins, &roster.loss,
&roster.tie) != EOF)
fprintf(afd, "%s Wins:%d Losses:%d ties:%d total league points:%d\n",
roster.team, roster.wins, roster.loss, roster.tie, (roster.wins *2 +
roster.tie *1 ), total, filename2);
printf("\nYour stats have been recorded to the selected
file!\nClosing all open files! \nThanks for using the STAT-Master!
Have a great day!
fclose(afd);
fclose(ifp);
return 0;
}
Your logic is quite jumbled. If I understand what you are attempting, you want to read each teams wins, loss and tie record from your data file, and then compute the points that are then used to sort the teams into descending (or perhaps ascending) order and then output the "the overall ALCentral Standings" to either stdout or a file, or both.
Before starting let's talk about your definition of struct records inside of main(). While legal, you generally will want your struct declaration to be at file scope so that the struct type is available to any functions you write to help process the data in your code. Here, you must move the declaration outside of main() because the qsort compare function will need to know what the type struct records is. The compare function cannot be declared and defined in main() because C does not allow nested function declarations. So move your struct outside of main(), e.g.
#define MAXR 16 /* if you need a constant, #define one (or more) */
#define MAXC 64
#define MAXB 1024
typedef struct records {
char team[MAXC];
int wins,
loss,
tie,
points;
} record_t;
(note: using a typedef can make things more convenient)
To begin with, your multiple attempts to read the filename is awkward and never insures you actually have a file open. It just makes a couple of attempts and then effectively gives up validation and just blindly assumes there is a valid file stream to read and write to and presses ahead. This is a recipe for invoking Undefined Behavior.
When ever you do anything in C, and especially when you are dealing with user input or file operations, you must validate every step. You must know whether or not the file is open for reading before you attempt to read. (no matter how many times you attempt to open it) You must validate what you have read before you begin using the values in your code. You must validate the state of your input stream before you attempt your next read, and handle any characters that remain.
With that in mind you can prompt for the filename and attempt to open the filename provided in a continual loop until you validate the file is actually open, e.g.
/** helper function to empty stdin between inputs */
void empty_stdin()
{
int c = getchar();
while (c != '\n' && c != EOF)
c = getchar();
}
...
FILE *fp = NULL; /* file pointer */
do { /* loop until valid filename given and file open */
printf("\nenter input filename: ");
if (scanf (" %63[^\n]", filename) != 1) {
fprintf (stderr, "error: user canceled input.\n");
return 1;
}
empty_stdin(); /* remove '\n' and any add'l chars in input buffer */
fp = fopen (filename, "r"); /* open filename */
if (fp == NULL) /* validate file open for reading */
perror ("fopen-input");
} while (fp == NULL);
printf("Opened file name %s\n\n",filename);
(note: rather than using scanf for user input, fgets provides a better approach to user input and far fewer pitfalls that scanf, example below with roster)
Next, your understanding of how to collect the data in memory in order to sort it, is not evident from your post. When you want to sort a collection of team information, you must read all team information into memory before you can pass the information to qsort for sorting.
You have a struct that holds all of information for each team, you simply need to read each line (record) from your input file into an array or struct which can then easily be passed to qsort for sorting.
To use qsort you first must define a compare function that is used to qsort to order your data. The compare function has a specific declaration:
int compare (const void *a, const void *b);
Where each const void * parameter will be a pointer to one of the elements in your array of records. (in C a void pointer, e.g. void* is a generic pointer that can be assigned from, or to, any other pointer type without a cast -- that is why the compare function's declaration uses that type for the parameters) Your job in writing a compare function is simply to provide a type to the pointers (either by assignment or by explicit cast, your choice) and then a comparison between the values that you wish to sort by. For example, your compare on the points member of each struct could simply be:
/** qsort compare function (descending order of points) */
int compare (const void *a, const void *b)
{
const record_t *ta = a;
const record_t *tb = b;
return (ta->points < tb->points) - (ta->points > tb->points);
}
(where the (a < b) - (a > b) simply evaluates to -1, 0, 1 depending on the inequalites, e.g. if a = 4 and b = 3, you have (0) - (1) which equals -1 meaning a sorts before b)
All that remains is reading each teams data into your array and computing points and then passing your array to qsort.
To read your data into an array, read each line into a buffer, parse the data in the buffer into the individual values, validate that each of the individual values where parsed correctly, compute the points value for each team, increment your array index and then go read the next line. You could do something like the following using fgets to read each line of data:
record_t roster[MAXR] = {{ .team = "" }}; /* array to hold teams */
...
/* read up to MAXR team records from file */
while (ndx < MAXR && fgets (buf, MAXB, fp)) {
/* parse data from buffer filled, saving return */
int rtn = sscanf (buf, " %49s %d %d %d" , roster[ndx].team,
&roster[ndx].wins, &roster[ndx].loss,
&roster[ndx].tie);
if (rtn < 4) /* if less than 4 conversions, get next line */
continue;
/* compute points (2 * wins + ties) */
roster[ndx].points = roster[ndx].wins * 2 + roster[ndx].tie;
ndx++; /* increment index */
}
fclose (fp); /* close file */
(note: you can add a strlen() check of buf to determine if additional characters remain in the line unread -- that is left to you).
With all you data in your array of structs roster, all that remains is passing roster to qsort and then outputting your sorted data.
The following sorts the data and outputs the results to stdout. Writing the output to a file is left to you, but hint, you don't need both ifp and afp and you don't need filename and filename2 or points2, you are only dealing with one file/filename at a time. The sort and output is simple:
/* sort roster based on points (descending order) */
qsort (roster, ndx, sizeof *roster, compare);
/* outpout results */
printf ("Here are the overall ALCentral Standings!\n\n"
"Team Wins Loss Tie Points\n\n");
for (int i = 0; i < ndx; i++)
printf ("%-12s %4d %4d %4d %4d\n", roster[i].team,
roster[i].wins, roster[i].loss, roster[i].tie,
roster[i].points);
Putting it altogether in an example, you could do something like the following:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAXR 16 /* if you need a constant, #define one (or more) */
#define MAXC 64
#define MAXB 1024
typedef struct records {
char team[MAXC];
int wins,
loss,
tie,
points;
} record_t;
/** helper function to empty stdin between inputs */
void empty_stdin()
{
int c = getchar();
while (c != '\n' && c != EOF)
c = getchar();
}
/** qsort compare function (descending order of points) */
int compare (const void *a, const void *b)
{
const record_t *ta = a;
const record_t *tb = b;
return (ta->points < tb->points) - (ta->points > tb->points);
}
int main (void) {
int ndx = 0; /* index for roster array */
char buf[MAXB] = "", /* buffer for fgetrs */
filename[MAXC] = ""; /* filename to read */
record_t roster[MAXR] = {{ .team = "" }}; /* array to hold teams */
FILE *fp = NULL; /* file pointer */
do { /* loop until valid filename given and file open */
printf("\nenter input filename: ");
if (scanf (" %63[^\n]", filename) != 1) {
fprintf (stderr, "error: user canceled input.\n");
return 1;
}
empty_stdin(); /* remove '\n' and any add'l chars in input buffer */
fp = fopen (filename, "r"); /* open filename */
if (fp == NULL) /* validate file open for reading */
perror ("fopen-input");
} while (fp == NULL);
printf("Opened file name %s\n\n",filename);
/* read up to MAXR team records from file */
while (ndx < MAXR && fgets (buf, MAXB, fp)) {
/* parse data from buffer filled, saving return */
int rtn = sscanf (buf, " %49s %d %d %d" , roster[ndx].team,
&roster[ndx].wins, &roster[ndx].loss,
&roster[ndx].tie);
if (rtn < 4) /* if less than 4 conversions, get next line */
continue;
/* compute points (2 * wins + ties) */
roster[ndx].points = roster[ndx].wins * 2 + roster[ndx].tie;
ndx++; /* increment index */
}
fclose (fp); /* close file */
/* sort roster based on points (descending order) */
qsort (roster, ndx, sizeof *roster, compare);
/* outpout results */
printf ("Here are the overall ALCentral Standings!\n\n"
"Team Wins Loss Tie Points\n\n");
for (int i = 0; i < ndx; i++)
printf ("%-12s %4d %4d %4d %4d\n", roster[i].team,
roster[i].wins, roster[i].loss, roster[i].tie,
roster[i].points);
return 0;
}
Example Input File
The file is provided as given, with blank lines in between records.
$ cat dat/teams.txt
Indians 54 45 5
Twins 45 53 7
Tigers 43 59 8
White_Sox 35 64 9
Royals 30 69 3
Example Use/Output
$ ./bin/qsortstrcmp
enter input filename: dat/teams.txt
Opened file name dat/teams.txt
Here are the overall ALCentral Standings!
Team Wins Loss Tie Points
Indians 54 45 5 113
Twins 45 53 7 97
Tigers 43 59 8 94
White_Sox 35 64 9 79
Royals 30 69 3 63
Look things over and let me know if you have further questions.

How to edit specific parts of a file based on user input in C?

I am doing a homework assignment that requires me to create a program for making a dictionary. Most of my assignment is done, but I am stuck on the most complicated part. The part of the assignment I'm stuck on reads:
Editing a Dictionary (E)
Insert a new word (I) (15 points)
If the word is available, it should alert a message.
Otherwise, insert the new word
Delete a word (D) (15 points)
If the word is not available, it should alert a message.
Otherwise, delete the word
Editing a word (U) (10 points)
If the word is not available, it should alert a message
Currently the file I am working with looks like this:
Name of product: Dictionary
Description: Spanish to English Dictionary
Developer: Robert
Date of Creation: 12/02/2017
Number of words: 0
***************************************************************************
1. Red Rojo
2. Cat Gato
3. Apple Manzana
4. Love Amor
5. Car Carro
and I am wondering how I can read, and do the operations above. Most of the stuff on google is very complicated for my current skillset. Here is what I have so far? Can someone ELI5 the general process of what I should be doing in this case? Should I be using structs? How can I interact with the file in the way my professor wants me to? Here is my basic code I have for this section so far:
int editDictionary(char *oDict) {
char array[1000];
char temp[100];
FILE * dictPtr; // dictPtr = dictionary.dic file pointer
/* fix directory for dictionaries */
strcat(temp,"./dicts/");
strcat(temp,oDict);
strcpy(oDict,temp);
/* open dictPtr file for rw */
dictPtr = fopen (oDict,"a+");
fscanf(dictPtr,"%s",array[1]);
/* text scan values */
for(int i = 0; i <5; i ++) printf("%s", array[i]);
return 1;
}
Your task is pretty tedious and requires knowledge of some inbuilt functions in C.
Since, this is your homework assignment, providing the entire code to you would do no good in improving your current skillset. So, I will provide the code for performing the delete operation the dictionary which is the trickiest of all. Rest you have to figure out yourself. The code in delete_dict is more than enough to help you write other functions.
I've added the explanations in the code for most of the functions used but you should still look up their documentation to understand what each function does.
Code:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
const char *WORD_COUNT_LABEL = "Number of words: ";
void delete_word(const char *filename, const char *word)
{
//add alerts
char read[100];
FILE *f = fopen(filename, "r");
int exists = 0; //the count of words that exist
//check if word exists
//fgets is used to read a line into the buffer/temp memory read
while (fgets(read, 100, f))
{
//strstr - finds substring
if (strstr(read, word))
{
exists++;
}
}
if (exists == 0)
{
fclose(f);
return;
}
//The main objective to read the file two times is
//because we want to edit the NUMBER_OF_WORDS in the file as well
//now we know that a word exists
//so move flie pointer to beginning
fseek(f, 0, SEEK_SET);
FILE *nf = fopen("dict_t.txt", "w");
int count;
char num[10];
char *p;
while (fgets(read, 100, f))
{
//if word count label is found update it
//return the pointer to the location of match
if (p = strstr(read, WORD_COUNT_LABEL))
{
p += strlen(WORD_COUNT_LABEL);
//incrementing the pointer to the position where number is to be updated
count = atoi(p); //converts integer from char * to int
count -= exists;
sprintf(num, "%d", count); //converts interger from int to char *
strcpy(p, num); //copy new number at that location
strcat(p, "\n");
}
else if (p = strstr(read, word))
{
//if we find the word to be deleted
//we set the first character in read as NULL
//so that nothing is written onto the new file.
read[0] = '\0';
}
//writes char * to file
fputs(read, nf);
}
//rest is self explanatory
fclose(nf);
fclose(f);
remove(filename);
rename("dict_t.txt", filename);
}

Reading a data file and storing into array of structures

I'm attempting to read a data file and to store the information into an array of course structures (or an array of pointers to course structures). This assignment requires maintaining a database using an array of pointers to the student structures.
I'm getting a segmentation fault when I attempt to scan the data file into the array. How can I properly store the information from the file into the array?
#define SIZE 30
#define fieldLength 300
#define diskFile "diskFile.dat"
#define courseFile "course.dat"
struct student
{
char name[fieldLength];
int age[fieldLength];
char course1[fieldLength];
char course2[fieldLength];
char remarks[fieldLength];
}*sp[SIZE];
struct course
{
char name[fieldLength];
char number[fieldLength];
char instructor[fieldLength];
char date[fieldLength];
char starting[fieldLength];
char ending[fieldLength];
char location[fieldLength];
};
int main(int argc, char *argv[])
{
int i, count;
struct course course_arr[SIZE]; // an array of ten structs
FILE * in; /*FILE pointer to do the stream IO*/
in = fopen(courseFile, "r+");
count = 0;
while ((fscanf(in, "%s %s %s %s %s %s %s",
&course_arr[count].name,
&course_arr[count].number,
&course_arr[count].instructor,
&course_arr[count].date,
&course_arr[count].starting,
&course_arr[count].ending,
&course_arr[count].location)) != EOF)
{
count++;
}
/* print the menu */
printf("\n-----------------------------------------------------------------\n");
printf("|\t%-20s","(N)ew record");
printf("%-20s","(U)pdate record");
printf("Swa(p) records\t|\n");
printf("|\t%-20s","(S)ort database");
printf("%-20s","(C)lear database");
printf("(D)isplay db\t|\n");
printf("|\t%-20s","(L)oad disk");
printf("%-20s","(W)rite disk");
printf("(E)mpty disk\t|\n");
printf("|\t%-20s", "(V)iew courses");
printf("%-20s","(R)emove record");
printf("(Q)uit \t|\n");
printf("-----------------------------------------------------------------\n");
printf("choose one: ");
Routine fscanf never returns EOF.
Test fscanf to be less than the number of expected fields:
count = 0;
while((fscanf(in, "%s %s %s %s %s %s %s", &course_arr[count].name, &course_arr[count].number, &course_arr[count].instructor, &course_arr[count].date, &course_arr[count].starting, &course_arr[count].ending, &course_arr[count].location)) < 7){
count++;
}
i think that it is better to work with
while(getline(string_variable,,)!=EOF).(look on the net on which argumentsto put in the getline)
Then work with the string_variable. Look at the format that the data is stored into the txt file. eg: name(blank)number(blank)instructor(blank)date(blank)starting(blank)endinglocation
Start looking for blanks in the string_variable. when you see the first blank copy the substring from position 1 to position blank-1 to the course_arr[count].name variable.then delete the substring from position 1 to position blank. Look again for the first blank and store the substring to course_arr[count].number and so on.
Sorry for my English hope u got the meaning
You should loose all the &s in the fscanf call. The char arrays are already passed as pointers. If you'd used the -Wall option on gcc (or a similar option for any other compiler) it will warn you for this as well.
Have you checked the file what you are reading is present or not.
add bellow
in = fopen(courseFile, "r+");
if(in == NULL)
{
printf("exit");
exit(0);
}
I guess it might be the problem.

Resources