rshptl rshptl - 4 months ago 11
C Question

read string char and int from file in c programming

student.dat file
----------------
Stu:1 abc ($) - 55 in following order (Stu: %d %s (%c) - %d)
Stu:2 pqr (^) - 82


I am trying to read this file and save highest grade details in the variable in c programming.
my code is below but is not complete!

int main(){

int num, grade;
char id, name[35];

FILE *fp = NULL;

fp = fopen("student.dat", "r");
if (fp != NULL) {

while ((fp != '\n') && (fp != EOF)) {

fscanf(fp, "%d %s %c %d", &num, name, id, &grade);
printf("Student Num: %d", num);
printf("Student Name: %s", name);
printf("Student id: %c", id);
printf("Student grade: %d", grade);

}

fclose(fp);
}else {
printf("Failed to open file\n");
}
}

Answer

In C, you have 2 primary ways to read line-oriented input and then parse into individual values (really 3, but we will ignore walking a pair of pointers down the string for now).

The preferred manner is to use a line-oriented input function such as fgets or POSIX getline to read an entire line into a buffer, and then parse the buffer with sscanf which can be done in a more flexible manner than a single call to fscanf.

Nonetheless, you appear dedicated to using fscanf here. The key to using fscanf successfully is to provide a format string that accounts for all characters in the line to be read, or to craft the format string to take advantage of properties of the individual format specifiers to accomplish the same thing (e.g. %s (as well as your numerical conversions) will skip leading whitespace giving you some control to deal with line-endings that would otherwise be left in the input-buffer (either the file or stdin and therefore be the next character available on a subsequent call to fscanf, which if not properly handled, will throw a wrench into your read routine.

Another mandatory step is to validate that all conversions specified were successfully completed during each read. You do that by checking the return value for fscanf which is the match count (a count of the number of successful conversions that took place). If you do not check, you cannot have any type of confidence that your values actually hold the data you think they do.

Putting that together, using your input file, and taking the filename to open as the first argument to the program (and reading by default on stdin if no filename is given), you could do something like the following:

#include <stdio.h>

int main (int argc, char **argv) {

    int num =0, grade = 0, max = 0;         /* initialize all variables */
    char id = 0, name[35];
    const char *fmt = " Stu:%d %s (%c) - %d";  /* given format string */
    FILE *fp = NULL;

    if (!(fp = argc > 1 ? fopen (argv[1], "r") : stdin)) {
        fprintf (stderr, "error: file open failed '%s'.\n", argv[1]);
        return 1;
    }
    /* read each line and validate 4 successful conversions */
    while (fscanf (fp, fmt, &num, name, &id, &grade) == 4) {
        if (grade > max) max = grade;
        printf ("Student Num: %d  Name: %-12s  id: %c  grade: %d\n",
                num, name, id, grade);         
    }
    printf ("\n highest grade : %d\n\n", max);

    if (fp != stdin) fclose (fp);

    return 0;
}

Example Use/Output

$ ./bin/stdntread <dat/stdntread.dat
Student Num: 1  Name: abc           id: $  grade: 55
Student Num: 2  Name: pqr           id: ^  grade: 82

 highest grade : 82

Look over the code, and especially the slight tweak to the format specifier, and let me know if you have any additional questions.