問題は次のfseek()
呼び出しである可能性があります。
fseek(ptr, -sizeof(BankAccount), SEEK_CUR);
からの戻り値sizeof()
は符号なしの型です。それの否定は非常に大きな数になるでしょう。技術的には、それは正しくありません (ではなくfseek()
を取得する必要があります)。ただし、場合は、それでうまくいきます(私にとってはうまくいきます)。long
size_t
sizeof(size_t) == sizeof(long)
問題のもう 1 つの側面は、(レコードが見つかったかどうかに関係なく) 戻る前にファイルを閉じていないことです。これは間違いなくメモリ リークです。データがディスクに書き込まれる方法にも影響する可能性があります。これがおそらくあなたの問題の根本原因です。ファイルを開いてデータを読み取って変更を確認する別の関数がありますが、ファイルが閉じられていないため、データはディスクに書き込まれていません。 注:ソースが利用可能になったので、これが問題の原因です。
データ構造を示していないため、別の問題は、型とメンバーの不一致である可能性がありますfloat
。同様に、唯一の問題は、口座残高に不適切なタイプであることです (たとえば、100,000.00 ドルを超える残高を最も近いセントまで確実に表すことはできません。たとえば、199999.99 と入力すると 199999.98 と表示されます)。double
balance
float
注: 最新バージョンの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% の確率で間違っています。