2

口座番号、クライアント名、銀行残高の 3 つの要素を持つ銀行クライアント (BankAccount) の構造体を持つプログラムを作成しています。すでにレコードが含まれているファイルがあり、残高を変更する機能があります。しかし、私はそうすることができません。バランスはそのままです。fseek() が間違っていると思いますが、その方法/理由がわかりません。fflush(stdin) を必要としない場所で使用しましたが、それが問題に関係しているとは思いません。私の概念に誤解がある場合に備えて、私の論理をお知らせするためにコメントしました。コードは次のとおりです。

 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();
}

実行したい場合に備えて、私のプロジェクトの .cpp ファイル全体を次に示します。ソース コード。いくつかのガイダンスをいただければ幸いです。前もって感謝します。

4

1 に答える 1

1

問題は次のfseek()呼び出しである可能性があります。

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

からの戻り値sizeof()は符号なしの型です。それの否定は非常に大きな数になるでしょう。技術的には、それは正しくありません (ではなくfseek()を取得する必要があります)。ただし、場合は、それでうまくいきます(私にとってはうまくいきます)。longsize_tsizeof(size_t) == sizeof(long)

問題のもう 1 つの側面は、(レコードが見つかったかどうかに関係なく) 戻る前にファイルを閉じていないことです。これは間違いなくメモリ リークです。データがディスクに書き込まれる方法にも影響する可能性があります。これがおそらくあなたの問題の根本原因です。ファイルを開いてデータを読み取って変更を確認する別の関数がありますが、ファイルが閉じられていないため、データはディスクに書き込まれていません。 注:ソースが利用可能になったので、これが問題の原因です。

データ構造を示していないため、別の問題は、型とメンバーの不一致である可能性がありますfloat。同様に、唯一の問題は、口座残高に不適切なタイプであることです (たとえば、100,000.00 ドルを超える残高を最も近いセントまで確実に表すことはできません。たとえば、199999.99 と入力すると 199999.98 と表示されます)。doublebalancefloat

注: 最新バージョンのLinuxおよびWindows ではfflush(stdin)は定義済みの操作です (定義済みの動作は理にかなっていて便利です)。C 標準および POSIX によると、未定義の動作が発生します。使用には注意してください — 移植可能な操作ではないことに注意してください。

SSCCE ( Short, Self-Contained, Correct Example ) に変換すると、コードをわずかに変更 (追加fclose())するだけでうまくいきます。

#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;
}

fseek()コンパイラは、コンパイラ オプションを使用した場合の変換についても気にしません。

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

実行すると、次のように表示されます。

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

関数内でファイルの終わりに達したかどうかを確認するための正しい形式に注意してくださいread()。を呼び出す場合feof()、99.9% の確率で間違っています。

于 2013-12-22T14:14:28.207 に答える