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:
I am trying to copy 65,536 lines from a file to an int array of the same size using a function.
each line contains four hexadecimal digits.
I also added _CRT_SECURE_NO_WARNINGS in properies => c/c++ => preprocessor definitions because i kept getting warnings because i was using f_gets and not f_gets_s to read from the file.
the error I keep getting now is:
Run-Time Check Failure #2 - Stack around the variable 'temp' was
corrupted.
when trying to print the array I see that all the lines are copied but the last line is copied twice or maybe copied once but is printed twice.
I don't understand what I'm doing wrong.
Thanks for the help.
#include <stdio.h>
#define NUMBER_OF_LINES_MEMO 65536
#define NUMBER_OF_REGISTERS 16
#define CHARS_IN_LINE 5
#define CHARS_IN_IMMEDIATE 5
#define _CRT_SECURE_NO_WARNINGS
void createFromFile(FILE *fPtrReadMemin, int *meminLines){
//create a new array of int numbers named meminLines, with the lines of memin text file
//gets pointers for the file memin and for the array meminLines
FILE *copyCreateFromFile = fPtrReadMemin;
int i = 0;
char temp[CHARS_IN_LINE]; //used for copying to the memory array
int temp2;
while (!feof(copyCreateFromFile))
{
fgets(temp, NUMBER_OF_LINES_MEMO, copyCreateFromFile);
if (strcmp(temp, "")==0)
{
break;
}
temp2 = (int)strtol(temp, NULL, 16);
meminLines[i] = temp2;
printf("%04x\n", temp2);
i++;
}
}
int main(int argc, char* argv[])
{
FILE*fPtrReadMemin;
fPtrReadMemin = fopen(argv[1], "r"); //open Memin to read
int meminLines[NUMBER_OF_LINES_MEMO]; // the memory
if (fPtrReadMemin == NULL) { //check if the files were open correctly
printf("There was error using files\n");
exit(1);
}
createFromFile(fPtrReadMemin, meminLines); //create the memory
system("pause");
fclose(fPtrReadMemin);//close all files
return 0;
}
Your buffer has a length of CHARS_IN_LINE:
char temp[CHARS_IN_LINE]; //used for copying to the memory array
But upon calling fgets you provide a buffer length of NUMBER_OF_LINES_MEMO:
fgets(temp, NUMBER_OF_LINES_MEMO, copyCreateFromFile);
You should provide the actual length of the temp buffer to fgets.
fgets(temp, CHARS_IN_LINE, copyCreateFromFile);
or even better
fgets(temp, sizeof temp, copyCreateFromFile);
Furthermore the length of the lines in your file is not 4 but 5, because fgets appends a \n at the end of the line. Therefore CHARS_IN_LINE should be at least 5.
Not directly related:
You can drop this line:
FILE *copyCreateFromFile = fPtrReadMemin;
and use directly fPtrReadMemin instead of copyCreateFromFile.
Your test of end of file is not correct, you should rather test if fgets returns NULL.
The strcmp is useless, you can drop it.
Overall corrected and simplified function:
void createFromFile(FILE *fPtrReadMemin, int *meminLines) {
//create a new array of int numbers named meminLines, with the lines of memin text file
//gets pointers for the file memin and for the array meminLines
int i = 0;
char temp[100]; // not using CHARS_IN_LINE but 100 which is a reasonable
// maximal file length.
while (fgets(temp, sizeof temp, fPtrReadMemin) != NULL)
{
meminLines[i] = (int)strtol(temp, NULL, 16);
printf("%04x\n", meminLines[i]);
i++;
}
}
And you forgot to include following:
#include <string.h>
#include <stdlib.h>
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.
I would like to know what is the best way to read a lines from files, given I have
a file, that I'm promised that it would be as followed:
type
string table
color
string brown
height
int 120
cost
double 129.90
each time, one word then I would have 2 words.
I know that fscanf returns the value of the numbers of var it scans, and that's
why I have problem here, because one time the line has 1 argument and the next line it would have 2.
always the first line is only a char*, not longer then 10, and then the next is has 3 options..
if it is written an int then the number followed would be an int, as well as if it a double or a string.
thank you.
From the structure of file i think it can be grouped into a struct. And fscanf can be used like:
#include <stdio.h>
#include <stdlib.h>
#define SIZE 100
typedef struct Node {
char name[SIZE];
char type[SIZE], value[SIZE];
} Node;
int main() {
FILE *pFile = fopen("sample-test.txt", "r");
if(pFile == NULL) {
fprintf(stderr, "Error in reading file\n");
return EXIT_FAILURE;
}
Node nodes[SIZE];
int nRet, nIndex = 0;
// Just to make sure it reads 3 tokens each time
while((nRet = fscanf(pFile, "%s%s%s", nodes[nIndex].name,
nodes[nIndex].type, nodes[nIndex].value) == 3))
nIndex++;
for(int i = 0; i < nIndex; i++)
printf("%s %s %s\n", nodes[i].name, nodes[i].type, nodes[i].value);
return EXIT_SUCCESS;
}
After reading the file, you can check in your structure array to find your desired int, double depending upon the value of name using sscanf as pointed by Some Programmer Dude.
I posted a problem yesterday regarding a certain segment of my code. The aim was to basically scan in data values from a .dat file into an array, print the values whilst also counting how many values were in the file.
Sounds pretty simple, but my program only seemed to print a certain number of the values. More specifically, of a data file containing over 300000 values, it would only print the last 20000 and nothing else.
So I left it, finished the rest of my code and now it's the last part I have to sort. I've made a few changes and tried actually printing an output .dat file now so I can see what I'm getting. The code is below by the way.
Initally I assumed perhaps it was something related to the memory allocation of my array (was getting a segmentation error? when putting the whole code together) so I created an external function that counted the number of values instead (that works).
My only problem now is that it still only chooses to print 20000 values and then the rest are 0s. I was thinking perhaps it had something to do with the type but they all contain 7 dps in scientific notation. Here's a sample of some of the values:
8.4730000e+01 1.0024256e+01
8.4740000e+01 8.2065599e+00
8.4750000e+01 8.3354644e+00
8.4760000e+01 8.3379525e+00
8.4770000e+01 9.8741315e+00
8.4780000e+01 9.0966478e+00
8.4790000e+01 9.4760274e+00
8.4800000e+01 7.1199807e+00
8.4810000e+01 7.1990172e+00
Anyone see where I'm going wrong? I'm sorry for the long question, it's just been bugging me for the last day or so and no matter what I change nothing seems to help. Any kind of input would be greatly appreciated.
#include <stdio.h>
#include <stdlib.h>
int count(int);
const char df[]="data_file.dat";
const char of[]="output_file.dat";
int main(int argc, char *argv[])
{
FILE *input, *output;
int i, N;
float *array;
N = count(i);
input = fopen(df, "r");
output = fopen(of, "w");
array = (float*)malloc(N*sizeof(float));
if((input != (FILE*) NULL) && (output != (FILE*) NULL))
{
for(i = 0; i < N; i++)
{
fscanf(input, "%e", &array[i]);
fprintf(output, "%d %e\n", i, array[i]);
}
fclose(input);
fclose(output);
}
else
printf("Input file could not be opened\n");
return(0);
}
int count(int i)
{
FILE *input;
input = fopen(df, "r");
int N = 0;
while (1)
{
i = fgetc(input);
if (i == EOF)
break;
++N;
}
fclose(input);
return(N);
}
Your biggest problem is that count() doesn't count float values; it counts how many characters are in the file. Then you try to loop and call fscanf() more times than there are values in the file. The first times, fscanf() finds a float value and scans it; but once the loop reaches the end of file, fscanf() will be returning an EOF status. It seems possible that fscanf() will set the float value to 0.0 when it returns EOF.
I suggest you rewrite so that you don't try to pre-count the float values. Write a loop that just repeatedly calls fscanf() until it returns an EOF result, then break out of the loop and close the files.
P.S. If you are going to write a function like count(), you should pass in the filename as an argument instead of hard-coding it. And your version of count() takes an integer argument but just ignores the value; instead, just declare a temp variable inside of count().
EDIT: Okay, here is a complete working program to solve this problem.
#include <stdio.h>
int
main(int argc, char **argv)
{
FILE *in_file, *out_file;
unsigned int i;
if (argc != 3)
{
fprintf(stderr, "Usage: this_program_name <input_file> <output_file>\n");
return 1; // error exit with status 1
}
in_file = fopen(argv[1], "r");
if (!in_file)
{
fprintf(stderr, "unable to open input file '%s'\n", argv[1]);
return 1; // error exit with status 1
}
out_file = fopen(argv[2], "w");
if (!out_file)
{
fprintf(stderr, "unable to open output file '%s'\n", argv[2]);
return 1; // error exit with status 1
}
for (i = 0; ; ++i)
{
int result;
float x;
result = fscanf(in_file, "%e", &x);
if (1 != result)
break;
fprintf(out_file, "%d %e\n", i, x);
}
return 0; // successful exit
}
Note that this version doesn't need to allocate a large array; it just needs a single temporary float variable. Maybe your program will need to store all the float values. In that case, write a count() function that uses a loop similar to the above loop, using fscanf() to count float values.
Also note that this program checks for errors after calling fopen() and fscanf().
You are allocating far more floats in memory (N) than you need because your N is the number of characters in the file, not the number of values in it.
Also, how did you determine that there are 300000 values in the file?