There are a lot of issues with your code. You are using feof
incorrectly. You must always add a width modifier to a conversion specifier that reads a string. You must check the value returned by scanf to ensure that it successfully matched input. I've tried to make minimal changes to the format strings you've used to demonstrate the form of the input that seems to be expected. Perhaps the reads into the unused character 'd' were attempts to match $
, but that is not imposed in your code (I've inserted d
in the input to be read by the fscanf(fp, "%c", &d)
). Since you've not provided a sample of the expected input, I've made some assumptions. If the input shown below does not match your expected input, you should modify your format strings. I am guessing you did not intend to match the literal s)
, but your current code requires those be in the input. Rather than more longwinded and probably poorly worded attempts at explanation:
$ gcc a.c
$ cat input
1$Alice $s)d 10d 5d 10d 15d 7
2$Bob $s)d 11d 6d 11d 16d 8
2$Chuck $s)d 12d 7d 12d 17d 9
$ echo input | ./a.out
Enter the file name: grade for Alice is 8.700000
grade for Bob is 9.700000
grade for Chuck is 10.700000
$ cat a.c
#include <stdio.h>
#include <stdlib.h>
int count;
int id[64];
char names[64][256];
double grades[64];
/* "filename" is a terrible name for a function that reads and parses data */
void
filename(const char *prompt)
{
char path[50];
FILE *fp;
char d;
int i;
double weight[] = { 0.15, 0.15, 0.25, 0.1, 0.35 };
printf("%s: ", prompt);
scanf("%49s", path); /* Always use a width modifier with %s!! */
if( (fp = fopen(path, "r")) == NULL ){
perror(path);
exit(EXIT_FAILURE);
}
count = 0;
while(
count < 64
&& 1 == fscanf(fp, "%d$", id + count)
&& 1 == fscanf(fp, "%255[^$]$s)", names[count])
){
grades[count] = 0;
for(i = 0; i < 5; i++) {
int s;
if( 0
|| 1 != fscanf(fp, "%c", &d)
|| 1 != fscanf(fp, "%d", &s)
){
fprintf(stderr, "Unexpected input\n");
goto end;
}
grades[count] += (double)s * weight[i];
}
printf("grade for %s is %f\n", names[count], grades[count]);
count += 1;
}
end:
fclose(fp);
}
int
main(void)
{
filename("Enter the file name");
return 0;
}
I would guess that your intent was to do something more like:
$ cat input2
1$Alice$ 10 $ 5 $ 10 $ 15 $ 7
2$Bob$ 11 $ 6 $ 11 $ 16 $ 8
3$Chuck$ 12 $ 7 $ 12 $ 17 $ 9
which could be parsed with:
#include <stdio.h>
#include <stdlib.h>
int count;
int id[64];
char names[64][256];
double grades[64];
void
parse_file(FILE *fp)
{
double weight[] = { 0.15, 0.15, 0.25, 0.1, 0.35 };
count = 0;
while(
count < 64
&& 1 == fscanf(fp, "%d", id + count)
&& 1 == fscanf(fp, "$ %255[^$]", names[count])
){
grades[count] = 0;
for( int i = 0; i < 5; i += 1 ){
int s;
if( 1 != fscanf(fp, " $%d", &s) ){
fprintf(stderr, "Unexpected input\n");
exit(EXIT_FAILURE);
}
grades[count] += (double)s * weight[i];
}
printf("grade for %s is %f\n", names[count], grades[count]);
count += 1;
}
}
int
main(int argc, char **argv)
{
const char *path = argc > 1 ? argv[1] : NULL;
FILE *fp = path ? fopen(path, "r") : stdin;
if( fp == NULL ){
perror(path);
exit(EXIT_FAILURE);
}
parse_file(fp);
fclose(fp);
return EXIT_SUCCESS;
}
Please note that this is functional, but certainly should not be considered robust. (For example, if there's a line with extra $ at the end, the program will merely abort with no error message.) It's not at all clear what behavior you want, so I'm not going to modify that but will merely remark that scanf
is absolutely the wrong tool for this. It is merely a toy that should only be used for educational purposes. Sadly, it should never be used for educational purposes, but is really just a toy to be used to confuse newbies. Please read http://sekrit.de/webdocs/c/beginners-guide-away-from-scanf.html