Question

I'm writing a program that has a struct for bank clients (BankAccount) having 3 elements - account number, name of client, and bank balance. I have a file with records already in it, and I have a function to modify the balance. However, I am unable to do so. The balance remains the same. I think my fseek() is wrong, but I'm not sure how/why. I've used fflush(stdin) in some places where it may not be required, but I don't think that's related to the problem. I've commented to let you know my logic, just in case there's some misunderstanding in my concepts. Here's the code:

 void modify(){

    int account_number;
    FILE *ptr;
    BankAccount account;

    ptr = fopen("account.txt", "r+");
    printf("Enter account number: ");
    fflush(stdin);
    scanf("%d", &account_number);

    while (!feof(ptr)) // To search the whole "account.txt" file.
    {
        fread(&account, sizeof(BankAccount), 1, ptr); //brings record into memory
        if (account.account_number == account_number){ // if record's account number is same as account number entered by user above
            printf("***Account found***\n\nAccount number: %d\nAccount name: %s\nAccount balance: %.2f\n", account.account_number, account.name, account.balance);
            printf("\nEnter new balance: ");
            fflush(stdin);
            scanf("%f", &account.balance); // rewrites account's balance in memory
            fseek(ptr, -sizeof(BankAccount), SEEK_CUR); //pointer seeked to the beginning of the record to overwrite it with the one in memory
            fwrite(&account,sizeof(BankAccount), 1, ptr); // record overwritten
            return;

        }
    }


    printf("Account not found\n");
    fflush(stdin);
    getch();
}

Here's the whole .cpp file of my project in case you'd like to run it : Source code. I'd appreciate some guidance. Thanks in advance.

Était-ce utile?

La solution

The problem could be the fseek() call:

fseek(ptr, -sizeof(BankAccount), SEEK_CUR);

The return value from sizeof() is an unsigned type; the negation of it is going to be a very large number. Technically, that's incorrect (fseek() should get a long, not a size_t). However, if sizeof(size_t) == sizeof(long), you get away with it (it works for me).

Another aspect of the problem could be that you don't close the file before you return (whether you find the record or not). That's most certainly a memory leak; it might also affect how the data is written to disk. This is probably the root cause of your trouble. You have another function the opens the file to read the data to see the changes, but since the file is not closed, the data has not been written to disk. Note: Since the source is now available, this is the cause of the problems.

Since you don't show us the data structure, another problem could be a mismatch of type float vs double for the balance member; equally, the only problem might be that float is an inappropriate type for account balances (it can't reliably represent balances above about $100,000.00 to the nearest cent, for example — e.g. entering 199999.99 is displayed as 199999.98).

Note: On modern versions of Linux and on Windows, fflush(stdin) is a defined operation (and the defined behaviour is sensible and useful). According to the C standard and POSIX, it yields undefined behaviour. Be cautious about using it — be aware that it is not a portable operation.

Converted into an SSCCE (Short, Self-Contained, Correct Example), a very slight modification of your code (adding fclose()) works for me:

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

typedef struct BankAccount
{
    int account_number;
    char   name[20];
    float balance;
} BankAccount;

static void modify(void)
{
    int account_number;
    FILE *ptr;
    BankAccount account;

    ptr = fopen("account.txt", "r+");
    printf("Enter account number: ");
    fflush(stdin);
    scanf("%d", &account_number);

    while (!feof(ptr))
    {
        fread(&account, sizeof(BankAccount), 1, ptr);
        printf("***Account read***(%d: %s: %.2f)\n", 
               account.account_number, account.name, account.balance);
        if (account.account_number == account_number)
        {
            printf("***Account found***\n\nAccount number: %d\nAccount name: %s\nAccount balance: %.2f\n", account.account_number, account.name, account.balance);
            printf("\nEnter new balance: ");
            fflush(stdin);
            scanf("%f", &account.balance);
            fseek(ptr, -sizeof(BankAccount), SEEK_CUR);
            fwrite(&account, sizeof(BankAccount), 1, ptr);
            fclose(ptr);
            return;
        }
    }

    printf("Account not found\n");
    fflush(stdin);
    fclose(ptr);
}

static void write(void)
{
    FILE *fp = fopen("account.txt", "w");
    if (fp == 0)
    {
        fprintf(stderr, "Create file failed\n");
        exit(1);
    }
    static const BankAccount data[] =
    {
        { 1, "His", 20.00 },
        { 2, "Hers", 2000.00 },
        { 3, "Theirs", 1.00 },
    };
    if (fwrite(data, sizeof(data), 1, fp) != 1)
    {
        fprintf(stderr, "Write file failed\n");
        exit(1);
    }
    fclose(fp);
}

static void read(void)
{
    FILE *fp = fopen("account.txt", "r");
    if (fp == 0)
    {
        fprintf(stderr, "Open file failed\n");
        exit(1);
    }
    BankAccount ac;
    while (fread(&ac, sizeof(ac), 1, fp) == 1)
    {
        printf("A/C: %4d %-20s  %8.2f\n", ac.account_number, ac.name, ac.balance);
    }
    fclose(fp);
}

int main(void)
{
    write();
    read();
    modify();
    read();
    return 0;
}

The compiler doesn't even witter about the conversion on the fseek() with the compiler options:

$ gcc -O3 -g -std=c11 -Wall -Wextra -Wmissing-prototypes -Wstrict-prototypes \
      -Wold-style-definition -Werror ba.c -o ba

When run, it shows:

A/C:    1 His                      20.00
A/C:    2 Hers                   2000.00
A/C:    3 Theirs                    1.00
Enter account number: 2
***Account read***(1: His: 20.00)
***Account read***(2: Hers: 2000.00)
***Account found***

Account number: 2
Account name: Hers
Account balance: 2000.00

Enter new balance: 4000
A/C:    1 His                      20.00
A/C:    2 Hers                   4000.00
A/C:    3 Theirs                    1.00

Note the correct form for checking whether you've reached the end of file in the function read(). If you call feof(), you are doing it wrong 99.9% of the time.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top