0

I'm trying to read different data types on the same line of a text file, and currently trying to store them in their own arrays via a structure. I'm not sure if this is the best course of action to begin with, but the point is to read data from a file and manipulate it using different functions. I thought that if I could extract the data from the file and store it in arrays, I could send the arrays into functions with the arrays as their parameters. Here's what I have, and the problem explained within the main function:

Driver File:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "student_struct.c"

struct Student{
   char name[50];
   int id;
   float gpa;
   int age;
};

int main(){

FILE *fptr;
fptr = fopen("student_records.txt", "r");

if (fptr == NULL){
    printf("Error opening file!\n");
    exit(1);
}

struct Student students[100];
int i = 0;

while(!feof(fptr)){
    //PROBLEM HERE. Data for what is expected to be in the "gpa" array is always 0.
    fscanf(fptr, "%c %d %f %d", &students[i].name[i], &students[i].id, &students[i].gpa, &students[i].age);
    i++;
}

fclose(fptr);

//Always prints "0.0000"
printf("GPA of student #2: %f\n", students[1].gpa);
//avgGPA(students.gpa);

return 0;
}

Function:

#include <stdio.h>


float avgGPA(float gpa[]){

int i;

float avgGPA = 0;
for(i = 0; i < sizeof(*gpa); i++){
    avgGPA += gpa[i];
}
avgGPA = avgGPA / sizeof(*gpa);
printf("Average GPA: %f", avgGPA);

}

Text file:

David 1234 4.0 44
Sally 4321 3.6 21
Bob 1111 2.5 20
Greg 9999 1.8 28
Heather 0000 3.2 22
Keith 3434 2.7 40
Pat 1122 1.0 31
Ann 6565 3.0 15
Mike 9898 2.0 29
Steve 1010 2.2 24
Kristie 2222 3.9 46

My question is, how do I properly pull the data from the file and use it in different functions? Thank you for your help.

help_me
  • 17
  • 5
  • Does this answer your question? [Why is “while ( !feof (file) )” always wrong?](https://stackoverflow.com/questions/5431941/why-is-while-feof-file-always-wrong) – KamilCuk Dec 03 '19 at 21:17
  • "don't think the data is properly being stored". Can you please be a bit more specific than that? Does the program crash? Does some of the data get parsed correctly but not others? Is it all garbage? Be as specific as you can. – kaylum Dec 03 '19 at 21:19
  • 2
    `%c` should be `%s` – kaylum Dec 03 '19 at 21:19
  • @kaylum, sorry! What I mean by that is that it seems each element of what I expect to be in the "gpa" array is always 0, when I'm expecting in the code above, it to be 3.6. – help_me Dec 03 '19 at 21:21
  • Please update the question with that info. – kaylum Dec 03 '19 at 21:22
  • @kaylum, huh. That seems to have done it. Thank you very much! – help_me Dec 03 '19 at 21:22
  • 1
    Great! Do you understand why? If not, please ask. Or read the details carefully in the `fscanf` man page for your reference. – kaylum Dec 03 '19 at 21:23
  • I do not understand why. Based on your response I can assume that it has something to do with the fscanf function, but I don't see what difference the %c makes in comparison to the %s. – help_me Dec 03 '19 at 21:25
  • @help_me what do you think `%c` and `%s` do? – bolov Dec 03 '19 at 21:26
  • I thought %c looked for a character, which makes me think %s takes a string, but if the array in the structure "Student" is made of characters, why does it properly function with a string? At that end, why does that influence the rest of the operation? – help_me Dec 03 '19 at 21:29
  • Note: you don't have an array of gpas, you have an array of `struct student`s. Each element of that array has an `int gpa` member. `avgGPA(students.gpa)` won't work, and the function will need refactoring. – LegendofPedro Dec 03 '19 at 21:55

1 Answers1

1

The %c in fscanf needs to be changed to %s. Refer to the fscanf man page for what each of the conversion specifiers mean. Specifically:

s

Matches a sequence of non-white-space characters; the next pointer must be a pointer to character array that is long enough to hold the input sequence and the terminating null byte ('\0'), which is added automatically. The input string stops at white space or at the maximum field width, whichever occurs first.

c

Matches a sequence of characters whose length is specified by the maximum field width (default 1); the next pointer must be a pointer to char, and there must be enough room for all the characters (no terminating null byte is added). The usual skip of leading white space is suppressed. To skip white space first, use an explicit space in the format.

In other words, %c by default only matches a single character. %s matches multiple non-white space characters (ie, colloquially a "word").

Other follow on questions you had:

  • but if the array in the structure "Student" is made of characters, why does it properly function with a string?

    • In C a string is defined as an array of characters terminated by a NUL (0).
  • At that end, why does that influence the rest of the operation?

    • %c will consume just one character. Which means the next modifier (%d in this case) will try to match with the remaining part of the first word and fail.

Other best practices that are relevant should be applied. Specifically:

  1. Always check the return value of function calls. fscanf in particular for this case. If that were done you would be able to see that fscanf had failed to match most of the modifiers.
  2. while !feof is always wrong. A full explanation of that is not provided here but please refer to other SO answers such as this.
  3. Use a debugger to step through your code to help you examine the state of variables to better understand what the program is doing and where things go wrong.
Community
  • 1
  • 1
kaylum
  • 13,833
  • 2
  • 22
  • 31