C覆盖文件中的现有记录

时间:2013-12-22 12:15:15

标签: c randomaccessfile

我正在编写一个程序,它有一个银行客户结构(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文件,以防你想要运行它:Source code。我很感激一些指导。提前谢谢。

1 个答案:

答案 0 :(得分:1)

问题可能是fseek()来电:

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

sizeof()的返回值是无符号类型;否定它将是一个非常大的数字。从技术上讲,这是不正确的(fseek()应该得到long,而不是size_t。但是,如果sizeof(size_t) == sizeof(long),你可以逃脱它(它对我有用)。

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

由于您没有向我们展示数据结构,因此float成员的另一个问题可能是doublebalance类型不匹配;同样,唯一的问题可能是float对于帐户余额来说是不合适的类型(例如,它不能可靠地代表大约$ 100,000.00以上的余额到最近的分数 - 例如输入199999.99显示为199999.98)。

注意:在LinuxWindows的现代版本上,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%的时间都做错了。