0

I have this code. Let's say I want to link flight 1 (generated with function InputFlight) to User 1 (generated with function InputUser). Note: struct user has another nested struct called booking, that has a nested struct called flight.

By moving with pointers through binary files all I do is:

Ask user a flight number (let's suppose the first flight) -> So I move to the first flight.

Ask user which user he is (let's suppose the first user) -> So I move to the first user.

Then through fread() and fwrite(), I try to copy what's inside the struct flight into travelers.b.list, but somehow it won't work.

I already tried everything. I tried changing parameters in fwrite() and fseek() but without success. I guess the main problem is in the function checkin() inside booking.h, but I can't seem to solve it.

main.c

#include <stdio.h>
#include <stdlib.h>

#include "flight.h"
#include "user.h"

void login_admin();

int main() {
    setbuf(stdout, NULL);

    login_admin();

return 0;
}

void login_admin() {

    FILE *file;
    FILE *file1;

    unsigned short int userchoice1 = 0;
    unsigned short int s = 0;

    while (s != 1) {    
        printf("\n-------------- M E N U --------------");
        printf("\n----- A D M I N I S T R A T O R -----");
        printf("\n1) Insert user");
        printf("\n2) Insert flight");
        printf("\n3) Check-in");
        printf("\n9) Exit program");
        printf("\n-------------------------------------");
        printf("\nYOUR CHOICE: ");
        scanf("%hu", &userchoice1);

        if (s != getchar()) {
        }
        switch (userchoice1) {
        case 1:
            inputUser(file);
            break;
        case 2:
            inputFlight(file);
            break;
        case 3:
            checkin(file, file1);
            break;
        case 9:
            s = 1;
            exit(0);
            break;
        default:
            printf("\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n");
            printf("\nValue not valid.");
            break;
        }
    }
}

booking.h

#include <stdio.h>

 typedef struct {
    flight list;
    char booking_code[MAX_BOOKING_CODE];
} booking; //struct booking

 typedef struct {
    char name[MAX_NAME];
    char surname[MAX_SURNAME];
    date date_of_birth;
    char place_of_birth[MAX_PLACE_OF_BIRTH];
    char passport_number[MAX_PASSPORT];
    booking b;
 } user; //struct user

void checkin(FILE *flights, FILE *users) {

    flight list;
    user travelers;

    int user_number = 0;
    int choice = 0;
    int choice1= 0;

    if( (users = fopen("users.dat", "rb") ) == NULL) {
        printf("Error.(1)");
    }
    else
    {
        printf("\nWhat's your user number?");
        printf("\nUSER NUMBER: ");
        scanf("%d", &user_number);
        fseek(users, (user_number-1)*sizeof(user), SEEK_SET);
        fread(&travelers, 1, sizeof(user), users);

        if( (flights = fopen("flights.dat", "rb") ) == NULL) {
            printf("Error.");
        }
        else {
            printf("Available flights:\n\n");

                flights = fopen("flights.dat", "rb");

                while( !(feof(flights)))
                {

                int read = fread(&list, 1, sizeof(flight), flights);
                if ( read > 0) {
                    printf("Flight code: %s\nCompany name: %s\nDEPARTURE FROM: %s\nARRIVAL AT: %s\nPlane code: %s\nDay of flight: %hu\nMonth of flight: %hu\n"
                            "Year of flight: %hu\nHour of departure: %hu:%hu\nHour of arrival: %hu:%hu\nFlight time: %hu min.\n\n",
                            list.flight_code, list.companyname, list.departure,
                            list.arrival, list.plane_code, list.date_of_flight.day,
                            list.date_of_flight.month, list.date_of_flight.year, list.hour_departure,
                            list.minute_departure,list.hour_arrival,list.hour_departure, list.flight_time);
                }

            }

            printf("Which flight you want to choose?\n");
            printf("YOUR CHOICE: ");
            scanf("%d", &choice1);

            fseek(flights, (choice1-1)*sizeof(flight), SEEK_SET);
            fread(&list, 1, sizeof(flight), flights);

            printf("\n--------YOU CHOSE FLIGHT %d-------- \n\n", choice1);
                    printf("Flight code: %s\nCompany name: %s\nDEPARTURE FROM: %s\nARRIVAL AT: %s\nPlane code: %s\nDay of flight: %hu\nMonth of flight: %hu\n"
                            "Year of flight: %hu\nHour of departure: %hu:%hu\nHour of arrival: %hu:%hu\nFlight time: %hu min.\n\n",
                            list.flight_code, list.companyname, list.departure,
                            list.arrival, list.plane_code, list.date_of_flight.day,
                            list.date_of_flight.month, list.date_of_flight.year, list.hour_departure,
                            list.minute_departure,list.hour_arrival,list.hour_departure, list.flight_time);


            users = fopen("users.dat", "rb+");
            fseek(users, (user_number-1)*sizeof(user), SEEK_SET);

            fwrite(&travelers.b.list, 1, sizeof(user), users);

            fclose(users);
            fclose(flights);

flight.h

#include <stdio.h>
#include "define.h"

typedef struct {
    unsigned short int day;
    unsigned short int month;
    unsigned short int year;
 } date; //struct date

 typedef struct {
    char flight_code[MAX_FLIGHT_CODE];
    char companyname[MAX_COMPANY_NAME];
    char departure[MAX_DEPARTURE];
    char arrival[MAX_ARRIVAL];
    char plane_code[MAX_PLANE_CODE];
    unsigned short int seats[MAX_SEATS];
    date date_of_flight;
    unsigned short int hour_departure;
    unsigned short int minute_departure;
    unsigned short int hour_arrival;
    unsigned short int minute_arrival;
    unsigned short int flight_time;
} flight; //struct flight

void inputFlight(FILE *flight_file);

void inputFlight(FILE *flight_file) {

    flight list;

    static int i = 0;

    //for (int i = 0; i < 20; i++) {

        flight_file = fopen("flights.dat","wb");
        printf("Flight code %d: ", i+1);
        scanf("%6s", list.flight_code);
        fflush(stdin);
        printf("Company name of flight %d: ", i+1);
        scanf("%19s", list.companyname);
        fflush(stdin);
        printf("DEPARTURE: ");
        scanf("%19s", list.departure);
        fflush(stdin);
        printf("ARRIVAL: ");
        scanf("%19s", list.arrival);
        fflush(stdin);
        printf("Plane code of flight %d: ", i+1);
        scanf("%4s", list.plane_code);
        fflush(stdin);
        printf("Day of flight %d: ", i+1);
        scanf("%hu", &list.date_of_flight.day);
        fflush(stdin);
        printf("Month of flight %d: ", i+1);
        scanf("%hu", &list.date_of_flight.month);
        fflush(stdin);
        printf("Year of flight %d: ", i+1);
        scanf("%hu", &list.date_of_flight.year);
        fflush(stdin);
        printf("Hour and minutes of departure flight %d (separated by spacebar): ", i+1);
        scanf("%hu%hu", &list.hour_departure, &list.minute_departure);
        fflush(stdin);
        printf("Hour and minutes of arrival flight %d (separated by spacebar): ", i+1);
        scanf("%hu%hu", &list.hour_arrival, &list.minute_arrival);
        fflush(stdin);
        printf("Flight time: ");
        scanf("%hu", &list.flight_time);
        fflush(stdin);

        fwrite(&list, 1, sizeof(flight), flight_file);

        fclose(flight_file);

    //}
}

user.h

#include <stdio.h>
#include <stdlib.h>
#include "booking.h"

void inputUser(FILE *input);

void inputUser(FILE *input) {


    if( (input = fopen("users.dat", "wb") ) == NULL) {
        printf("Error.");
    }
    else {

        user travelers;

        static int i = 0;

        //for (int p = 0; p < 3; p++) {

            printf("Name user %d: ", i+1);
            scanf("%19s", travelers.name);
            fflush(stdin);
            printf("Surname user %d: ", i+1);
            scanf("%19s", travelers.surname);
            fflush(stdin);
            printf("Day of birth user %d: ", i+1);
            scanf("%hu", &travelers.date_of_birth.day);
            fflush(stdin);
            printf("Month of birth user %d: ", i+1);
            scanf("%hu", &travelers.date_of_birth.month);
            fflush(stdin);
            printf("Year of birth user %d: ", i+1);
            scanf("%hu", &travelers.date_of_birth.year);
            fflush(stdin);
            printf("Place of birth user %d: ", i+1);
            scanf("%9s", travelers.place_of_birth);
            fflush(stdin);
            printf("Passport number user %d: ", i+1);
            scanf("%8s", travelers.passport_number);
            fflush(stdin);

            fwrite(&travelers, 1, sizeof(user), input);
            i++;

        //}

        fclose(input);
    }
}

define.h

#ifndef DEFINE_H_
#define DEFINE_H_

#define MAX_NAME 20
#define MAX_SURNAME 20
#define MAX_PASSPORT 9
#define MAX_PLACE_OF_BIRTH 15

#define MAX_FLIGHT_CODE 6
#define MAX_COMPANY_NAME 20
#define MAX_DEPARTURE 20
#define MAX_ARRIVAL 20
#define MAX_PLANE_CODE 5
#define MAX_SEATS 150

#define MAX_BOOKING_CODE 5

#endif /* DEFINE_H_ */

Expected results are that struct list, seeked (basically chosen) through fseek() in function checkin() should be saved inside the struct travelers.b.list, while all I get is a mix of various symbols etc when I try to printf it.

I hope I got everything clear for you and sorry in advance for the bad formatting etc.

This is a really big University project for me, I hope someone can help me out.

Thank you.

SlimShadys
  • 119
  • 3
  • 17
  • You do not give a way to reproduce your problem but I put some remarks in an answer (editing it several times, sorry) about 'perfectible' parts of your code. I do not say that in my answer but to put definition of functions in the header files is not a good idea, use several source files – bruno May 14 '19 at 21:54
  • 1
    I would recommend just not putting structs in binary files, ever, because it's not portable. Define your binary file in a way specifies the byte-per-byte values directly and do the needed conversions, possibly with the help of a serialization library. – aschepler May 14 '19 at 22:05
  • @bruno Definition of functons in .h and the function itself in the related .c is a choice given by our teacher. I can't do anything about it. – SlimShadys May 14 '19 at 22:43
  • @SlimShadys normaly we put declaration of functions in h files, not their definitions, are you sure to understand your teacher request ? – bruno May 14 '19 at 22:45
  • @aschepler Can you please elaborate your answer? You mean I shouldn't save my structs in a binary file? If so, how could I move the pointer in the file itself and do the needed edits? (_Since the administrator can change the flight time, or the name of the company for ex._) – SlimShadys May 14 '19 at 22:46
  • @bruno Yes Bruno, I was wrong. Declarations in .h, while definitions in .c, I know. While our teacher said that everything must be in a .h that you can include. – SlimShadys May 14 '19 at 22:48
  • @SlimShadys to save struct using fwrite is not portable because depends on endianness and size of used types, more the way the compiler place the fields in struct, the padding etc – bruno May 14 '19 at 22:48
  • @bruno If so, how do you suggest me to save my structs? Through a simple text file? If I do that, I won't be able to edit a _x_ user (as far as my skills in C allow) – SlimShadys May 14 '19 at 22:59
  • @SlimShadys this is not because this a text than the size cannot be constant – bruno May 15 '19 at 06:52

1 Answers1

1

In inputUser you write doing

fwrite(&travelers, 1, sizeof(user), input);

it seems more logical to do

fwrite(&travelers, sizeof(user), 1, input);

because fwrite is

size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream);

rather than

size_t fwrite(const void *ptr, size_t nmemb, size_t size, FILE *stream);

Of course it is the same elsewhere like in checkIn, and for the fread where you also exchange nmemb and size


Note in checkin you do two times flights = fopen("flights.dat", "rb") :

    if( (flights = fopen("flights.dat", "rb") ) == NULL) {
        printf("Error.");
    }
    else {
        printf("Available flights:\n\n");

            flights = fopen("flights.dat", "rb");

because you use the same variable flights only the second FILE can be closed. After a time you will not be able to open again a file because the number of open file at the same time is limited.


Warning

 while( !(feof(flights)))

generally does not work, use the result of fread to stop to read


You can remove all your fflush(stdin);, they do nothing :

For input streams associated with seekable files (e.g., disk files, but not pipes or terminals), fflush() discards any buffered data ...


I encourage you to check the result of your scanf to be sure a valid input was enter, so to check it returns 1 when you read a value and 2 the few cases you read 2 values

Also in

   scanf("%d", &user_number);
   fseek(users, (user_number-1)*sizeof(user), SEEK_SET);
   fread(&travelers, 1, sizeof(user), users);

and

       scanf("%d", &choice1);

       fseek(flights, (choice1-1)*sizeof(flight), SEEK_SET);
       fread(&list, 1, sizeof(flight), flights);

there is no check at all

So you do not know what you read, you suppose a valid int was enter for user_number and choice1, you suppose their value is compatible with the size of the file, then you suppose you can read a user/fligh

You really need to add checks


I guess the main problem is in the function checkin() inside booking.h

Yes, in checkin your way to modify the flight part of a user is not the right, you do

 fseek(users, (user_number-1)*sizeof(user), SEEK_SET);

 fwrite(&travelers.b.list, 1, sizeof(user), users);

the fseek set the position at the beginning of the user in the file, but rather than to fwrite all the user you fwrite the sub part travelers.b.list so you replace name/surname/... by the flight (and the memory after it because you write the size of the user rather than on the the size of a flight) which furthermore is not initialized because previously you fread in the variable list rather than in travelers.b.list.

A way to correct can be to update travelers.b.list then to write all the user, so to replace

       fread(&list, 1, sizeof(flight), flights);

       printf("\n--------YOU CHOSE FLIGHT %d-------- \n\n", choice1);
               printf("Flight code: %s\nCompany name: %s\nDEPARTURE FROM: %s\nARRIVAL AT: %s\nPlane code: %s\nDay of flight: %hu\nMonth of flight: %hu\n"
                       "Year of flight: %hu\nHour of departure: %hu:%hu\nHour of arrival: %hu:%hu\nFlight time: %hu min.\n\n",
                       list.flight_code, list.companyname, list.departure,
                       list.arrival, list.plane_code, list.date_of_flight.day,
                       list.date_of_flight.month, list.date_of_flight.year, list.hour_departure,
                       list.minute_departure,list.hour_arrival,list.hour_departure, list.flight_time);


       users = fopen("users.dat", "rb+");
       fseek(users, (user_number-1)*sizeof(user), SEEK_SET);

       fwrite(&travelers.b.list, 1, sizeof(user), users);

by

        fread(&travelers.b.list, sizeof(flight), 1, flights);

        printf("\n--------YOU CHOSE FLIGHT %d-------- \n\n", choice1);
                printf("Flight code: %s\nCompany name: %s\nDEPARTURE FROM: %s\nARRIVAL AT: %s\nPlane code: %s\nDay of flight: %hu\nMonth of flight: %hu\n"
                        "Year of flight: %hu\nHour of departure: %hu:%hu\nHour of arrival: %hu:%hu\nFlight time: %hu min.\n\n",
                        travelers.b.list.flight_code, travelers.b.list.companyname, travelers.b.list.departure,
                        travelers.b.list.arrival, travelers.b.list.plane_code, travelers.b.list.date_of_flight.day,
                        travelers.b.list.date_of_flight.month, travelers.b.list.date_of_flight.year, travelers.b.list.hour_departure,
                        travelers.b.list.minute_departure,travelers.b.list.hour_arrival,travelers.b.list.hour_departure, travelers.b.list.flight_time);


        users = fopen("users.dat", "rb+");
        fseek(users, (user_number-1)*sizeof(user), SEEK_SET);

        fwrite(&travelers, sizeof(user), 1, users);

An other way closer to your code is to fseek at the right position and to write the right flight with the right size, so to replace

 fseek(users, (user_number-1)*sizeof(user), SEEK_SET);

 fwrite(&travelers.b.list, 1, sizeof(user), users);

by

 fseek(users, (user_number-1)*sizeof(user) + (((char *) &travelers.b.list) - ((char *) &travelers)), SEEK_SET);

 fwrite(&list, sizeof(list), 1, users);
bruno
  • 32,421
  • 7
  • 25
  • 37
  • Okay. I did all the changes you mentioned. 1) Changed fwrite() and fread() arguments as you showed. 2) Opened flights.dat just once 3) Instead of feof, I used `while( read != 0 )` as condition to read all the file. 4) Removed all the `fflush(stdin);`. Should I implement `gets()` instead of `scanf()`? 5) I'm just trying to link user1 with flight1, so my choice (as for now) will be always 1 in _user_number_ and _choice1_. I'll implement various checks as I fix my main problem -> Copy the struct got from `fread(&list, 1, sizeof(flight), flights);` into travelers.b.list in _checkIn()_. – SlimShadys May 14 '19 at 22:41
  • @SlimShadys When you say "_I get is a mix of various symbols etc_" is it during execution or inside the produced files ? If in file this is normal because you write non initialized bytes in them – bruno May 14 '19 at 22:44
  • @SlimShadys Not sure you see the question in my remark above because of the remarks on your question. Anyway time to sleep for me, it is 1am here... – bruno May 14 '19 at 22:54
  • This is what I mean: https://imgur.com/gallery/lLPkJe8 First terminal: I'm able to create a new user. Of course all the variables in _travelers.b.list_ are empty as I haven't written on them. Second terminal: I try to link the flight 1 to user 1 (it basically means that i'm now populating _travelers.b.list_) but somehow the terminal messes up. The point 4) basically just does a `fread()` of file users.dat – SlimShadys May 14 '19 at 22:56
  • @SlimShadys ok I understand now your main problem, I edited my answer to add the reason and way to solve it at the end of my answer – bruno May 15 '19 at 08:05
  • That works perfectly. Changed the **_fseek()_** and **_fwrite()_** as you showed me and now I can successfully link flight 1 with user 1. Just a quick question tho: if you look at the _booking struct_, I have a field called **_booking_code_**. If I want to modify that booking_code for a specific user, I'll use that fseek(user_number - 1) to move to the right user, but how can I change only the booking_code field? Should I do ` + (((char *) &travelers.b.booking_code) - ((char *) &travelers)) ` instead of ` + (((char *) &travelers.b.list) - ((char *) &travelers)) ` in **fseek()**? Thank you. – SlimShadys May 15 '19 at 12:26
  • 1
    @SlimShadys yes, this is a way to compute the right offset. Warning also to write the right size of data – bruno May 15 '19 at 12:28