I am doing a practice problem for my C programming class which tells me to write a program that reads in variables from a file. On the first line, it is supposed to read in an integer N.
From there, it should read an integer, and then five floating points on every line for N lines. It is supposed to calculate a sum of all the floats in the file and write it to another file.
I have written a program that should do this using fgets to copy a line to a string, and sscanf to dissect it and assign the segments to different array locations. However, I am encountering some issue with obtaining extraneous information through sscanf (perhaps a null value or the newline). It is not storing the integer N properly (it is producing large random values and creating a runtime error by infinite loop), and it probably isn't working inside of the loop either.
How can I perfect this so that it reads in the integers and floats properly?
#include <stdio.h>
#include <stdlib.h>
#define MAX_STRING 30
#define MAX_LINE_SIZE 200
int main(void)
{
FILE *f1, *f2;
char filename[MAX_STRING];
char fileline[MAX_LINE_SIZE];
int N, eN;
float totalwage = 0;
int* ssn;
float** wage;
printf ("Enter a file name for data analysis: ");
scanf ("%s", &filename); //get file name from user input for reading
f1 = fopen (filename, "r");
fgets (fileline, MAX_LINE_SIZE, f1); //read first line
sscanf (fileline, "%d", &N); //pull integer from first line to determine how many lines follow
for (eN = 0; eN < N; eN ++) //read N lines following the first
{
// VVV read single line from file
fgets (fileline, MAX_LINE_SIZE, f1);
// VVV record data from line
sscanf (fileline, "%d, %f, %f, %f, %f, %f", &ssn[eN], &wage[eN][0], &wage[eN][1], &wage[eN][2], &wage[eN][3], &wage[eN][4]);
// VVV add the 5 wages on each line to a total
totalwage += wage[eN][0] + wage[eN][1] + wage[eN][2] + wage[eN][3] + wage[eN][4];
}
fclose (f1);
printf ("Enter a file name for the result: ");
scanf ("%s", &filename); //get file name from user input for writing
f2 = fopen (filename, "w");
fprintf (f2, "%f", totalwage); //store total of wages in file specified by user
printf ("\nThe information has been stored. Press any key to exit.\n");
getchar();
}
The file being read is 'wages.txt' and it's contents are as follows:
10
1, 10, 20, 30, 40, 50
2, 11, 12, 13, 14, 15
3, 21, 23, 25, 27, 29
4, 1, 2, 3, 4, 5
5, 30, 60, 90, 120, 150
6, 37, 38, 39, 40, 41
7, 40, 50, 60, 70, 80
8, 5, 10, 15, 20, 25
9, 80, 90, 100, 110, 120
10, 1000, 2000, 3000, 4000, 2000
As a recap, the issue is that there is a runtime error in which the program crashes due to some sort of infinite loop. Through some debugging I saw that it was not reading in the first line as an integer properly. Instead of the value ten, it was storing large values as though it read a null character.
I have added code in attempt to allocate memory for ssn and wages. However, I am not sure if it was done correctly, and the program still has a crashing runtime error.
ssn = malloc (N*MAX_STRING);
wage = malloc (N*MAX_STRING);
for (eN = 0; eN < N; eN ++)
{
wage[eN] = malloc (N*MAX_STRING);
}
As pointed out by others
scanf ("%s", &filename);
should be:
scanf ("%s", filename);
Note that sscanf
is a big problem if the number of columns change
Revised for use with strtod
:
#include <stdio.h>
#include <stdlib.h>
#define MAX_STRING 30
#define MAX_LINE_SIZE 200
#define COLS 5
int main(void)
{
FILE *f1, *f2;
char filename[MAX_STRING];
char fileline[MAX_LINE_SIZE];
int N, eN, i;
float totalwage = 0;
float (*wage)[COLS];
char *p;
printf ("Enter a file name for data analysis: ");
scanf ("%s", filename); //get file name from user input for reading
f1 = fopen (filename, "r");
fgets (fileline, MAX_LINE_SIZE, f1); //read first line
sscanf (fileline, "%d", &N); //pull integer from first line to determine how many lines follow
wage = malloc((sizeof(float) * COLS) * N);
/* check malloc ... */
for (eN = 0; eN < N; eN ++) //read N lines following the first
{
// VVV read single line from file
p = fgets (fileline, MAX_LINE_SIZE, f1);
strtol(p, &p, 10); /* skip first column */
for (i = 0; i < COLS; i++) {
wage[eN][i] = strtod(p + 1, &p); /* p+1 skip comma, read a float */
totalwage += wage[eN][i]; /* sum */
}
}
free(wage);
fclose (f1);
printf ("Enter a file name for the result: ");
scanf ("%s", filename); //get file name from user input for writing
f2 = fopen (filename, "w");
fprintf (f2, "%f", totalwage); //store total of wages in file specified by user
printf ("\nThe information has been stored. Press any key to exit.\n");
getchar();
fclose(f2); /* you forget to close f2 */
return 0;
}
Also note that you are reading floats only for sum, there is no need to store them, so malloc
can be avoided, and in the real world check the result of fopen
, fgets
...