If you want a short example to help get you started, the first thing to keep in mind when reading strings into a character array (buffer) is Don't Skimp on Buffer Size!. Using 10
and 20
may cut it for the small set of data you have shown, but what happens when you try and read Mandheling Black
? Take your longest anticipated string and at minimum, double that number of characters when using a fixed array (if it is a single buffer to be reused such as for reading each line, a 1K buffer size is fine, 2K is also fine)
Try to avoid using MagicNumbers like 10
and 20
, instead:
#include <stdio.h>
#define MAXC 1024 /* if you need a constant, #define one (or more) */
#define MAXNM 32 /* (don't skimp on buffer size) */
#define MAXCT 16
typedef struct cofeeshop { /* typedef avoid writing 'struct name' in code */
char cofeeName [MAXNM],
cofeeColor [MAXNM],
cofeeWorld [MAXNM];
int CofeePockets,
onePocketSize;
} cofeeshop;
...
If you note above, a typedef
of struct cofeeshop
is created in the name cofeeshop
. By creating a typedef
, you can simply use cofeeshop
as the type anywhere it is needed in your code instead of having to write struct cofeeshop
each time.
What you need to actually read from your file, is a buffer (character array) large enough to hold each line, a counter to keep track of how many coffee types you have read, and then an array of cofeeshop
to hold the values contained in each line. You can do that while taking the filename to read from as the first argument to your program (or read from stdin
if no argument is given) as follows:
int main (int argc, char **argv) {
char line[MAXC]; /* buffer to hold each line */
cofeeshop cofee[MAXCT] = {{.cofeeName = ""}}; /* array of chofeeshop */
size_t n = 0; /* cofeetype counter */
/* use filename provided as 1st argument (stdin by default) */
FILE *fp = argc > 1 ? fopen (argv[1], "r") : stdin;
if (!fp) { /* validate file open for reading */
perror ("file open failed");
return 1;
}
...
Note above you always VALIDATE the return from any input/output function used, including whether fopen()
succeeded or failed, Before you attempt to read from the file.
You can then read each line from the file with fgets()
into your buffer line
and then pass line
to sscanf()
to separate the parts of line
into the next available element in your array of struct, cofee
, e.g.
...
/* while array not full, read each line in file and add to array */
while (n < MAXCT && fgets (line, MAXC, fp)) {
/* separate into name, color, world, pockets, size & VALIDATE return */
if (sscanf (line, "%s %s %s %d %d", cofee[n].cofeeName, cofee[n].cofeeColor,
cofee[n].cofeeWorld, &cofee[n].CofeePockets,
&cofee[n].onePocketSize) == 5) {
n++; /* increment cofeetype counter */
}
}
...
Note: you VALIDATE the return of sscanf()
to check that the conversion with each format-specifier in the format-string "%s %s %s %d %d"
succeeded. There are five format-specifiers in the format-string, so you check that the return == 5
before considering the variables to be filled with valid input from line
.
At this point your reading of input is done, so simply close the file if not reading from stdin
and output all values stored in your array to stdout
, e.g.
...
if (fp != stdin) /* close file if not stdin */
fclose (fp);
for (size_t i = 0; i < n; i++) /* output stored values */
printf ("%-12s %-12s %-12s %4d %4d\n", cofee[i].cofeeName, cofee[i].cofeeColor,
cofee[i].cofeeWorld, cofee[i].CofeePockets, cofee[i].onePocketSize);
}
All that remains is writing the values to an output file in a format of your choosing -- that is left to you.
Putting it altogether (that is the full code above), you would have:
#include <stdio.h>
#define MAXC 1024 /* if you need a constant, #define one (or more) */
#define MAXNM 32 /* (don't skimp on buffer size) */
#define MAXCT 16
typedef struct cofeeshop { /* typedef avoid writing 'struct name' in code */
char cofeeName [MAXNM],
cofeeColor [MAXNM],
cofeeWorld [MAXNM];
int CofeePockets,
onePocketSize;
} cofeeshop;
int main (int argc, char **argv) {
char line[MAXC]; /* buffer to hold each line */
cofeeshop cofee[MAXCT] = {{.cofeeName = ""}}; /* array of chofeeshop */
size_t n = 0; /* cofeetype counter */
/* use filename provided as 1st argument (stdin by default) */
FILE *fp = argc > 1 ? fopen (argv[1], "r") : stdin;
if (!fp) { /* validate file open for reading */
perror ("file open failed");
return 1;
}
/* while array not full, read each line in file and add to array */
while (n < MAXCT && fgets (line, MAXC, fp)) {
/* separate into name, color, world, pockets, size & VALIDATE return */
if (sscanf (line, "%s %s %s %d %d", cofee[n].cofeeName, cofee[n].cofeeColor,
cofee[n].cofeeWorld, &cofee[n].CofeePockets,
&cofee[n].onePocketSize) == 5) {
n++; /* increment cofeetype counter */
}
}
if (fp != stdin) /* close file if not stdin */
fclose (fp);
for (size_t i = 0; i < n; i++) /* output stored values */
printf ("%-12s %-12s %-12s %4d %4d\n", cofee[i].cofeeName, cofee[i].cofeeColor,
cofee[i].cofeeWorld, cofee[i].CofeePockets, cofee[i].onePocketSize);
}
Compile
Compile your program with full warnings enabled, every time -- and do not accept code until it compiles without warning, e.g.
gcc -Wall -Wextra -pedantic -Wshadow -std=c11 -Ofast -o bin/cofeeshop cofeeshop.c
-Wall -Wextra -pedantic
enable full warnings for gcc/clang, add -Wshadow
to catch any shadowed variables (like i
declared and used in two different scopes in your code that may cause problems). For VS use /W3
for full warnings. For other compilers, just read the option documentation to determine what is needed.
Example Use/Output
With your sample data in the file dat/cofeeshop.txt
, you would have:
$ ./bin/cofeeshop dat/cofeeshop.txt
Lavazza Gray Europe 433 10
Machito Black Europe 433 10
Machito White Asia 24 18
Chiley Black Asia 198 17
Hucki White America 11 11
If you wanted to test reading from stdin
, you could just redirect the input file on stdin
, e.g.:
$ ./bin/cofeeshop < dat/cofeeshop.txt
Lavazza Gray Europe 433 10
Machito Black Europe 433 10
Machito White Asia 24 18
Chiley Black Asia 198 17
Hucki White America 11 11
Look things over and let me know if you have further questions.
(note: cofee
is generally spelled coffee
-- but will go with what you have :)