-1

i write managment system in C. i have this structure

#define STRING_LENGTH 32
typedef struct {
    char name[STRING_LENGTH];
} Name;

typedef struct{
    int id, balance;
    Name clientName;
} Client;

i create few test objects, open binary file for write, use fwrite to write objects to file, closing it and after this using fread into while(!feof... block, and my problem is that i print 4 objects to binary file, and while i read objects from file and print it to screen, last object printed twice. what i do incorrect? i need only to write objects to file and then get them back from it.

my code:

FILE *clientsFile = NULL;

switch (selectedOption)
{
case CLIENT:

        clientsFile = fopen(CLIENTS_FILE_PATH, "wb");

        Client getUser;
        Client temp1 = { 1, 10000, "Alex" };
        Client temp2 = { 2, 100000, "Valery" };
        Client temp3 = { 3, 105466, "Jack" };
        Client temp4 = { 4, 1069640, "Pam" };

        fwrite(&temp1, sizeof(Client), 1, clientsFile);
        fwrite(&temp2, sizeof(Client), 1, clientsFile);
        fwrite(&temp3, sizeof(Client), 1, clientsFile);
        fwrite(&temp4, sizeof(Client), 1, clientsFile);

        fclose(clientsFile);

        clientsFile = fopen(CLIENTS_FILE_PATH, "rb");

        do
        {               
            fread(&getUser, sizeof(Client), 1, clientsFile);
            printf("ID : %d, Name : %s, Balance : %d\n", getUser.id, getUser.clientName.name, getUser.balance);
        } while (!feof(clientsFile));

        break;

output photo : screen of output

thanks for answers

Alex S
  • 66
  • 5

3 Answers3

2

feof() returns true if the end of file indicator flag has been raised. A successful call to fread() will not result in raising the flag. Thus, after reading the last record, you iterate one more time.

Instead, check to see if fread() was successful to decide if you have reached end of file or encountered some other error.

    do
    {               
        if (fread(&getUser, sizeof(Client), 1, clientsFile) == 1) {
            printf("ID : %d, Name : %s, Balance : %d\n", getUser.id, getUser.clientName.name, getUser.balance);
        } else {
            /* do something */
        }
    } while (!feof(clientsFile));
jxh
  • 69,070
  • 8
  • 110
  • 193
2

My way is to do it like this. If you read the correct number of records, fine, if not, quit. There is no need to involve feof().

while(fread(&getUser, sizeof(Client), 1, clientsFile) == 1) {
    printf("ID : %d, Name : %s, Balance : %d\n", getUser.id, getUser.clientName.name, getUser.balance);
}
Weather Vane
  • 33,872
  • 7
  • 36
  • 56
1

It is because you are using do-while.

do
{               
    fread(&getUser, sizeof(Client), 1, clientsFile);
    printf("ID : %d, Name : %s, Balance : %d\n", getUser.id, getUser.clientName.name, getUser.balance);
} while (!feof(clientsFile));

In this, when you read for the 5th time you get EOF. But "getUser" still has the 4th Client entry. So you get last output twice.

Solution: Change it to while loop.

while (fread(&getUser, sizeof(Client), 1, clientsFile) && !feof(clientsFile))
{
    printf("ID : %d, Name : %s, Balance : %d\n", getUser.id, getUser.clientName.name, getUser.balance);
}
MayurK
  • 1,925
  • 14
  • 27
  • What happens if an error occurs when calling fread()? AFAICT, feof() will return 0 and the program will be stuck in an eternal loop, right? – Bjorn A. Oct 21 '16 at 18:29
  • Not very elegant because you have the exact same `fread` in two different places. – Jabberwocky Oct 21 '16 at 18:31
  • BjornA. and Micheal, I agree to both the points. Thank you. I updated my answer. Is it fine now? – MayurK Oct 21 '16 at 18:35