C 覆盖文件中的现有记录

C 覆盖文件中的现有记录,c,randomaccessfile,C,Randomaccessfile,我正在写一个程序,它有一个银行客户结构(BankAccount),有3个元素——账号、客户名称和银行余额。我有一个已经有记录的文件,我有一个修改余额的函数。但是,我不能这样做。余额保持不变。我认为我的fseek()是错的,但我不知道怎么做/为什么。我在一些可能不需要的地方使用了fflush(stdin),但我认为这与问题无关。我发表评论是为了让你知道我的逻辑,以防在我的概念中有一些误解。代码如下: void modify(){ int account_number; FILE

我正在写一个程序,它有一个银行客户结构(BankAccount),有3个元素——账号、客户名称和银行余额。我有一个已经有记录的文件,我有一个修改余额的函数。但是,我不能这样做。余额保持不变。我认为我的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文件,以防您想要运行它:。我希望得到一些指导。提前感谢。

问题可能是
fseek()
调用:

fseek(ptr, -sizeof(BankAccount), SEEK_CUR);
sizeof()
的返回值是无符号类型;对它的否定将是一个非常大的数字。从技术上讲,这是不正确的(
fseek()
应该是
long
,而不是
size\u t
)。但是,如果
sizeof(size\u t)==sizeof(long)
,您就可以摆脱它(它对我有效)

问题的另一个方面可能是在返回之前没有关闭文件(无论是否找到记录)。这肯定是内存泄漏;它还可能影响数据写入磁盘的方式。这可能是你麻烦的根本原因。您还有另一个函数打开文件以读取数据以查看更改,但由于文件未关闭,因此数据尚未写入磁盘注意:由于源现在可用,这就是问题的原因

由于您没有向我们显示数据结构,另一个问题可能是
余额
成员的
float
类型与
double
类型不匹配;同样,唯一的问题可能是,
浮动
对于账户余额来说是一种不合适的类型(例如,它不能可靠地表示超过100000.00美元到最接近的美分的余额-例如,输入199999.99显示为199999.98)

注意:在和的现代版本上,
fflush(stdin)
是一个定义的操作(定义的行为是合理和有用的)。根据C标准和POSIX,它产生未定义的行为。使用时要小心-注意它不是便携式操作

转换为SSCCE(),对您的代码稍加修改(添加
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;
}
运行时,它会显示:

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%的时间都是错误的。

C文件没有任何记录(或某些其他结构)。它们只是一个字节流(或序列)。你考虑过了吗?你的代码是在什么操作系统上运行的?@BasileStarynkevitch我是学习CS的大一新生。我们刚刚开始学习C中的FileIO,所以我不知道运行Windows 8的GDBM或SQlite(尽管我认为它们与数据库和其他东西有关?)。@mbrach是的,我可以看到“找到帐户”以及帐户详细信息。我也可以为新的余额进行输入,但是当我再次打印记录时,余额不会被覆盖(有另一个功能)。我很抱歉二进制的东西,我不明白。你所说的“二进制读/写”到底是什么意思?
而(!feof(ptr))
滥用警告。。。这个while循环表示:“虽然我们还没有读过EOF,但是在读do时没有发生错误…”@EliasVanOotegem um。。。我不明白。使用这个错误吗?我希望循环一直运行到它的account.number==account\u number。为此,它必须搜索文件中的所有记录,对吗?还有其他方法吗?谢谢您的调试!我完全忘记了fclose(),尽管我在其他函数中使用了它。让我意识到这有多重要。另外,我不知道我检查EOF的方法是错误的,谢谢。每当scanf()或get()时,我都使用命令fflush(stdin),否则会导致问题。我在这里用的次数比我应该用的多,所以也谢谢你提醒我。不客气。请注意,还有一些其他小问题,例如在三个函数中的每个函数中重复文件名;应该在变量或常量中定义一次,并将变量传递给各个函数。我的代码使用
write()
read()
;它们也是POSIX定义的函数名。编写的代码是安全的(并且可以在POSIX ish系统上工作),但实际上应该使用其他名称。我没有将您的代码升级为错误检查
scanf()
调用;应检查-应检查所有输入(和打开)操作。小心在没有提示的情况下使用
getch()
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