下面我提供了我的代码。我要根据提供的帐号“存入”钱。名称,帐号和余额都在以下“ accounts.dat”文件中。
Herman T Travis 3 $500
Sam L Travis 1 $40
Henry O Billiam 2 $6000
我不确定创建文件的方式(使用简单的vi编辑器)还是代码中的问题,但是当我运行该文件并将帐号和余额提供给程序时,不会报告该错误。文件中的新余额。有什么建议吗?
#include <stdio.h>
#include <stdlib.h>
typedef struct {
char first[15];
char middle[2];
char last[15];
float balance;
long int acct;
} data;
int main() {
int choice = -1, i = 0, n = 0;
long int number;
double amount;
FILE *aPtr;
data accounts[50];
aPtr = fopen("accounts.dat", "ab+");/* Opens file for read/write; appends to file if exist */
if (aPtr == NULL) {
printf("File could not be opened");
exit(1);
}
fseek(aPtr, 0, SEEK_SET); /* Moving pointer to start of file*/
while (fread(accounts + 1, sizeof(data), 1, aPtr) == 1) /* Read and store info in file, into accounts array */
i++;
n = i; /* Num. of records in file */
do {
printf("Select Option\n" );
printf("0: Exit\n1: Deposit\n2: Withdrawl\n3: Add Account\n4: Remove Account\n5: Balance Inquiry\n6: View Accounts\n: ");
scanf("%d", &choice);
switch (choice) {
case 0: /* Exit */
fclose(aPtr);
break;
case 1: /* Deposit*/
fseek(aPtr, 0, SEEK_SET);
printf("Enter account number:\n");
scanf("%ld", &number);
printf("Enter amount to be deposited:\n");
scanf("%lf", &amount);
for (i = 0; i < n; i++) {
if (accounts[i].acct == number) {
accounts[i].balance = accounts[i].balance + amount;
fseek(aPtr, i * sizeof(data), SEEK_SET); /* Pointer goes to accountlocation in file*/
fwrite(accounts + i, sizeof(data), 1, aPtr); /* Write modified account into file */
break;
}
}
if (i == n) {
printf ( "Account does not exist\n" );
}
break;
}
} while (choice != 0);
return 0;
}
答案 0 :(得分:0)
此while
循环读取数据不正确
while( fread(accounts+1, sizeof(data), 1, aPtr) == 1 ) /* Read and store info in file, into accounts array */
i++;
它只是读入accounts[1]
,所以无论文件中有多少个帐户,数组中都只有一个。
您要做的是将每条记录读入accounts[i]
中,这是下面的代码。
while( fread(&accounts[i], sizeof(data), 1, aPtr) == 1 ) /* Read and store info in file, into accounts array */
i++;
或者更好,如果您计算出文件的大小
fseek(aPtr, 0, SEEK_END);
unsigned long len = (unsigned long)ftell(aPtr);
那么您知道len
除以sizeof(data)
是多少个记录
n = len/sizeof(data);
您可以一次性读取所有记录。
if(fread(accounts, sizeof(data), n, aPtr) != n)
{
/* Oops! Did not read everything in */
}
这具有您可以使用malloc
的附加好处,因此您不必设置50个帐户的硬限制。
打开文件的方式也不正确,因为无论您用fseek
做什么,它都会将您写入的内容附加到文件末尾。您需要改用“ rb +”,但是如果文件不存在,则需要首先使用“ wb +”创建它。
答案 1 :(得分:0)
正确填充结构是此答案的重点。
文件的命名约定表示该文件应为二进制文件(即.dat
在业界通常用于二进制文件)。但是您显示的内容清楚地表明它是一个文本文件,因此在以下示例中,我使用data.txt作为文件名。而且,由于它是一个文本文件,并且包含定义明确的行字段,因此将内容解析为struct会很简单
文件的格式是严格定义的,并使用空格作为分隔符。没关系,但是选择一个在字段内容中通常不使用的可见分隔符(例如逗号:,
)会在不使用字段(例如没有中间名)时使事情变得容易。但这不是必需的,下面的示例将使用空格分隔符。
如果您将在此实现中避免使用fgets()
和strtok()
(几乎没有错误检查/处理),则提供了一个使用数据文件内容填充结构的示例:
typedef struct
{
char first[15];
char middle[2];
char last[15];
float balance;
long int acct;
}DATA;
const char filename[] = {".\\data.txt"};
int lineCount(const char *fname);
DATA * populateData(int lines, const char *fname);
int main(void)
{
int lines = lineCount(filename);//count number of accounts in file (lines in file)
DATA *data = populateData(lines, filename);//Create and populate data structure
if(data)
{
; //use data here
free(data); //free data memory when finished using it.
}
return 0;
}
int lineCount(const char *fname)
{
int count=0;
char line[260];
FILE *fp = fopen(fname, "r");
if(fp)
{
while(fgets(line, 260, fp)) count++;
fclose(fp);
}
return count;
}
DATA * populateData(int lines, const char *fname)
{
int i;
char *tok;
char *endPtr;
char line[260];
DATA *data = calloc(lines, sizeof(*data ));
if(data)
{
FILE *fp = fopen(fname, "r");
if(fp)
{
for(i=0;i<lines;i++)
{
if(fgets(line, 260, fp))
{
//get first name
tok = strtok(line, " ");
if(tok)
{
strcpy(data[i].first, tok);
//get Middle name
tok = strtok(NULL, " ");
if(tok)
{
strcpy(data[i].middle, tok);
//get last name
tok = strtok(NULL, " ");
if(tok)
{
strcpy(data[i].last, tok);
//get balance
tok = strtok(NULL, " ");
if(tok)
{
data[i].acct = atoi(tok);
//get acct
tok = strtok(NULL, "$");
if(tok)
{
data[i].balance = strtod(tok, &endPtr);
}
}
}
}
}
}
}
fclose(fp);
}
}
return data;
}
答案 2 :(得分:0)
您的程序中存在一个主要错误:
while (fread(accounts + 1, sizeof(data), 1, aPtr) == 1) /* Read and store info in file, into accounts array */
没有{
来将所有语句括在一个块中。因此,i++;
语句中仅重复第一个(while
),其余仅执行一次。
我的建议是:
{
和}
将所有命令语句括在块中。{
与if
,while
放在同一行,以用于and
switch`语句(这种样式称为 Kernighan和Ritchie < / em>)。if (i == n) { printf("Account does not exist\n"); }
的形式包装语句关于程序的目标,您无法轻松地尝试更新文本文件。要么将整个文件读入内存结构,然后从内存中写入更新的内容,要么使用具有固定宽度字段的二进制格式。
Unix的哲学是偏爱前一种方法,而将后者保留给具有高级API的大型数据库,以正确解决并发访问问题。
答案 3 :(得分:0)
还要在写入文件时添加fflush。在fflush()上查看您的文档。