1

I am wondering how to edit my code to swap loading iformation b typing it, to load it from file. I was looking at it for 2 hours but I did not bring up any result so I am trying to find some help here. In file it should look like this for students:

name study_year score

name study_year score

my code:

#include <stdio.h>
#include <string.h>

struct Teacher
{
    char name[50];
    int age;
};

struct Student
{
    char name[50];
    int study_year;
    float score; // 0.0 -- 100.0
};


void getT(struct Teacher *t)
{
    printf("Enter teacher's name: ");
    fgets(t->name, sizeof t->name, stdin);

    size_t len = strlen(t->name);
    if ('\n' == t->name[len - 1]) t->name[len - 1] = '\0';

    printf("Enter techaer's age: ");
    scanf("%d", &t->age);
    getchar();

    putchar('\n');
}

void getS(struct Student *s)
{
    printf("Enter student's name: ");
    fgets(s->name, sizeof s->name, stdin);

    size_t len = strlen(s->name);
    if ('\n' == s->name[len - 1]) s->name[len - 1] = '\0';

    printf("Enter student's study year: ");
    scanf("%d", &s->study_year);
    getchar();

    printf("Enter student's score: ");
    scanf("%f", &s->score); // tu bolo chybne "%d"
    getchar();

    putchar('\n');
}


void printT(struct Teacher t)
{
    printf(
        "Ucitel: %s\n"
        "   Vek: %d\n\n",
        t.name, t.age);
}

void printS(struct Student s)
{
    printf(
        "Student: %s\n"
        "  Rok studia:       %d\n"
        "  Studijny priemer: %.2f\n\n",
        s.name, s.study_year, s.score);
}


void main()
{
    struct Teacher t1;

    int count = 2; //pocet studentov

    struct Student ss[count];

    getT(&t1);

    for (int i = 0; i < count; ++i)
        getS(&ss[i]);

    printT(t1);
    // printS(s1);

    for (int i = 0; i < count; ++i)
        printS(ss[i]);

    printf("Teacher's size: %d\n", sizeof(struct Teacher));
    printf("Student's size: %d\n", sizeof(struct Student));

    return 0;
}

Thank you for all suggestions and answers.

  • 1
    Suggest editing post and changing out `"name study_year score"` for actual values you might find in the file, eg: `"William 2020 98.0"`, just to eliminate any questions on interpretation. Aside, an [easier way to remove a new line](https://stackoverflow.com/a/28462221/645128): `s->name[strcspn(s->name, "\n")] = 0;` – ryyker Feb 17 '21 at 18:36

2 Answers2

0

I would use the fread function to read the structures, and the fwrite function to write them. Say you have an array of SIZE students you want to write to a file:

struct Student students[SIZE];

// Populate your structs...

FILE *fp = fopen("myfile.bin", "wb");
fwrite(students, sizeof(struct Student), SIZE, fp);
fclose(fp);

Then, to read them back, first verify that the size of the file is a multiple of the size of your struct, in bytes, then read them from the file:

struct Student *students = NULL; // Dynamic since we don't know the size until we look at the file
FILE *fp = fopen("myfile.bin", "rb");
struct stat stats; // include <sys\stat.h>

stat("myfile.bin", &stats);
if( (stats.st_size % sizeof(struct Student)) != 0) 
{
    // This file is not composed of a series of 'struct Students' in order; print 'invalid file' message and exit
}

students = malloc(stats.st_size);
if(NULL == students)
{
     // Malloc failed; handle error
}
fread(students, sizeof(struct Student), (stats.st_size / sizeof(struct Student)), fp);
fclose(fp);

// 'students' is now populated with the file contents


free(students);
students = NULL;

Also note that the 'size check' to verify that you're working with a correct file is a very simplistic approach; proprietary file formats usually use magic numbers to identify what type of file they are.

Govind Parmar
  • 20,656
  • 7
  • 53
  • 85
0

Look into the fscanf family of functions, which are the opposite of the fprintf family. You for example your teacher structure could be encoded using:

void write_teacher(FILE *f, struct Teacher *teacher) {
    // This prints the name, followed by a space, and then the age
    fprintf(f, "%s %d\n", &teacher->name[0], teacher->age);
}

On the other hand, reading it almost the exact opposite:

int read_teacher(FILE *f, struct Teacher *teacher) {
    int count;
    // zero out the structure, you may also want to replace that 50
    // with a sizeof expression
    memset(&teacher->name[0], 0, 50);

    // here the 49 means that a maximum of 49 characters should be read
    // for the name. This reading happens until whitespace is encountered
    // so if there are spaces in the name, you will have to break it up.
    count = fscanf(f, "%49s %d\n", &teacher->name[0], &teacher->age);

    // fscanf returns the number of arguments converted, we want 2 conversions
    // so it should be 2 if it was successful.
    return count != 2; // returns 1 on error, 0 on success
}

scanf is quite well suited for applications like this, but it does have its shortcomings, see this article for some common issues and how to resolve them.

brenden
  • 574
  • 3
  • 16