I'm trying to separate my input values into 2 different categories. The first array call teamname would hold the the team names and the second array would hold the score for that week. My input file is .csv with the code the way it is everything is stored in the as a string instead of 2 separate variables. Also I'm not to program savvy and am only familiar with the library.
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#define FILEIN "data.csv"
#define FILEOUT "matrix.csv"
int main (void)
{
double nfl[32][32], teamscore[32];
char teamname[30];
int n;
FILE *filein_ptr;
FILE *fileout_ptr;
filein_ptr = fopen (FILEIN, "r");
fileout_ptr = fopen (FILEOUT, "w");
for (n = 1; n <= 32; n++) {
fscanf (filein_ptr, "%s %lf\n", &teamname, &teamscore[n]);
fprintf (fileout_ptr, "%s %f\n", teamname, teamscore);
}
fclose (filein_ptr);
fclose (fileout_ptr);
return 0;
}
I should say that the input file has the first column with team names and the second column with team scores. Any help would be great. Thanks! Here is a sample input file
- Steelers,20
- Patriots,25
- Raiders,15
- Chiefs,35
If you are going to store the team names in an array you should declare a two dimensional array:
Then, you declare the array for the score. You are using doubles to store the score, aren't them only integers?
To read those values you can use:
You need the [^,] to stop scanf from reading the string when finds a , The main will be something like:
In addition to changing
&teamname
toteamname
, there are a few other considerations you may want to look at. The first being, always initialize your variables. While not required, this has a number of positive benefits. For numerical arrays, it initializes all elements preventing an accidental read from an uninitialized value. For character arrays, initializing to0
insures that the first copy to the string (less than the total length) will benull-terminated
and also prevents an attempted read from an uninitialized value. It's just good habit:You have defined default values for your
filein_ptr
andfileout_ptr
, you can do the same for your array sizes. That makes your code easier to maintain by providing a single value to update if your array size needs change.Next, and this is rather a nit, but an important nit.
main
accept arguments, defined by standard asint argc, char **argv
(you may also see anchar **envp
on Unix systems, you may seem them both written in equivalent formchar *argv[]
andchar *envp[]
). The point here is to use them to take arguments for your program so you are not stuck with just your hardcodeddata.csv
andmatrix.csv
filenames. You can use your hardcoded values and still provided the user the ability to enter filenames of his choice by using a simpleternary
operator (e.g.test ? if true code : if false code;
):There, the test
argc > 1
(meaning there is at least one argument given by the user), if true codeopen (argv[1], "r")
(open the filename given as the argument for reading, and if false codefopen (FILEIN, "r")
open your default if not filename given. The same holds true for your output file. (you must provide them in the correct order).Then if you open a file, you must validate that the file is actually open before you attempt to read from it. While you can test the input and output separately to tell which one failed, you can also use a simple
||
condition to check if either open failed:Lastly, if you know the number of lines of data you need to read, an indexed
for
loop as you have is fine, but you will rarely know the number of lines in a data file before hand. Even if using afor
loop, you still need to check the return offscanf
to verify that you actually had 2 valid conversion (and therefore got 2 values you were expecting). Checking the return also provides another benefit. It allows you to continue reading until you no longer get 2 valid conversions fromfscanf
. This provides an easy way to read an unknown number of values from a file. However, you do need to insure you do not try and read more values into your array than they will hold. e.g.:note: when using a format specifier that contains a character case (like
"%[^,], ..."
), be aware it will read and include leading and trailing whitespace in the conversion to string. So if your file has' Steelers ,..'
,teamname
will include the whitespace. You can fix the leading whitespace by including a space before the start of the conversion (like" %29[^,], ..."
) and also limit the number of characters that can be read by specifying a maximum field width. (a trailing whitespace in the case would be easier trimmed after the read)Putting all the pieces together, you could make your code more flexible and reliable by taking arguments from the user, and validating your file and read operations:
Test Input
note: the variations in leading whitespace and whitespace between values was intentional.
Use/Output
Let me know if you have further questions.