문제는 fseek()
호출 될 수있다 :
fseek(ptr, -sizeof(BankAccount), SEEK_CUR);
sizeof()
의 반환 값은 부호없는 형식입니다; 그것의 부정은 아주 큰 숫자가 될 것입니다. 기술적으로 올바르지 않습니다 (fseek()
은 이 아닌 long
이됩니다). 그러나, sizeof(size_t) == sizeof(long)
이라면, 그걸 가지고 도망 갈 수 있습니다.
문제의 또 다른 측면은 반환 여부 (레코드를 찾았는지 여부)에 관계없이 파일을 닫지 않는 것일 수 있습니다. 그것은 확실히 메모리 누수입니다. 데이터가 디스크에 기록되는 방식에도 영향을 줄 수 있습니다. 이것은 아마도 문제의 근본 원인 일 것입니다. 파일을 열어 변경 내용을 볼 수있는 다른 기능이 있지만 파일이 닫히지 않아 데이터가 디스크에 기록되지 않았습니다. 참고 : 이제 소스를 사용할 수 있으므로 이것이 문제의 원인입니다.
데이터 구조를 표시하지 않으므로 balance
멤버의 경우 float
대 double
유형이 일치하지 않을 수 있습니다. 마찬가지로 float
은 계좌 잔액에 대해 부적절한 유형일 수 있습니다 (예 : 약 100,000.00 달러를 가장 가까운 센트로 신뢰 할 수는 없습니다. 예를 들어, 199999.99를 입력하면 199999.98로 표시됩니다).
참고 : 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()
의 변환에 대해조차 한 Witter을한다 옵션 :
실행
$ 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 %의 시간을 잘못하고있는 것입니다.
파일에는 레코드 (또는 다른 구조)가 없습니다.그것들은 바이트 스트림 (또는 시퀀스) 일뿐입니다. [GDBM] (http://www.gnu.org.ua/software/gdbm/) 또는 [SQlite] (http://www.sqlite.org/)를 고려 했습니까? 코드가 실행되는 운영 체제는 무엇입니까? –
@BasileStarynkevitch 저는 CS를 공부하는 신입생입니다. 우리는 C로 FileIO를 배우기 시작 했으므로 GDBM이나 SQlite에 대해서는 전혀 몰랐습니다. (데이터베이스와 관련이 있다고 생각 하지만요?) Windows 8을 실행 중입니다. – MMA
@mbratch 예, 저는 계정 정보와 함께 "*** Account found ***"를 참조하십시오. 또한 새 잔액에 대한 입력을 할 수 있지만 레코드를 다시 인쇄 할 때 잔액을 겹쳐 쓰지 않습니다 (다른 기능이 있음). 그리고 이진 파일에 대해 유감스럽게 생각합니다. 이해가 안됩니다. "바이너리로 읽기/쓰기"란 정확히 무엇을 의미합니까? – MMA