我在大学有一个作业,我们需要读取两个 .dat (aascii) 文件,这些文件是我们用早期程序创建的,这两个文件都是排序的。
一个是包含客户余额、帐号和名称的客户帐户文件,另一个是包含帐号和该帐户交易的交易文件。
该程序必须匹配帐号并创建一个新的和更新的客户文件,方法是根据帐号将交易金额添加到客户的余额中。
我的工作正常,除非有重复的交易,例如,如果交易文件包含第二个客户的 2 个单独的交易,我的代码将在两次交易后打印更新的余额而不是累积余额。
我只是想知道是否有人可以阐明如何解决这个问题。我的代码已附上,在此先感谢。
#include <stdio.h>
#include <conio.h>
int main()
{
int account,matches=0; /* account number */
char date[ 30 ]; /* account Date */
double balance, saleamount,total=0, x; /* account SaleAmount */
int transaccount;
char name [ 30 ];
FILE *cfPtr; /* cfPtr = clients.dat file pointer */
FILE *ctPtr; /* cfPtr = transaction.dat file pointer */
FILE *cfPtr2; /* cfPtr2 = new client file */
cfPtr2 = fopen( "clientupdate.dat", "w" );
/* fopen opens file; exits program if file cannot be opened */
if ( ( cfPtr = fopen( "clients.dat", "r" ) ) == NULL ) {
printf( "clients could not be opened\n" );
fflush(stdin);
} /* end if */
else
if( ( ctPtr = fopen( "transactions.dat", "r" ) ) == NULL)
{
printf( "File could not be opened\n" );
fflush(stdin);
}
else { /* read account, date,name, balance and SaleAmount from files */
fscanf( cfPtr, "%d%s%lf", &account, &name, &balance );
fflush(stdin);
fscanf( ctPtr, "%d%s%lf", &transaccount, &date, &saleamount );
fflush(stdin);
printf( "%-13s%-10s%s\n", " Account", "Name", "Balance" );
printf("|----------------------------------|\n");
while( !feof(ctPtr))
{
while( !feof(cfPtr) &&matches==0 )
{
if(account == transaccount)
{
matches=1;
total=0;
x = balance+saleamount;
total = total + x;
balance = total;
printf(" %-10d%-10s%.2lf\n", account, name, total);
}
else
{
fscanf( cfPtr, "%d%s%lf", &account, &name, &balance );
fflush(stdin);
}
}
fprintf( cfPtr2, "%d %s %.2lf\n", account, name, total );
fscanf( ctPtr, "%d%s%lf", &transaccount, &date, &saleamount );
fflush(stdin);
matches=0;
}
fclose( cfPtr2 );
getch();
}
最佳答案
虽然我不敢相信他们实际上仍在教授 COBOL(以 C 为幌子),但我会帮助你,因为与一些在这里寻求帮助的人不同,你实际上已经投入了大量工作:- )
诀窍是不要在每次更新后打印,而是等到帐号转换后打印出之前的最终详细信息。
而且,由于在处理最后一个帐户时您将到达交易文件的末尾,因此您必须在退出循环后再执行一次。
这是详细的步骤。
再引入三个变量,char lastname[30]
, int lastaccount
和 double lastbalance
.确保 lastaccount
初始化为 -1
.
然后您的代码可以通过简单地检查 lastaccount
的值来捕获帐号的转换。和 account
.所有三个字段的存储是为了确保您可以打印出以前帐户的详细信息,即使您已经阅读了新帐户的详细信息。
之前 matches = 1
,插入以下代码:
if (lastaccount != account) {
if (lastaccount != -1)
printf(" %-10d%-10s%.2lf\n", lastaccount, lastname, lastbalance);
lastaccount = account;
strcpy (lastname, name);
}
您还需要包含
string.h
获取 strcpy
的原型(prototype).这将捕获帐号的转换并打印最后一个的详细信息(除非最后一个是帐号
-1
,当然因为这意味着没有前一个)。但无论它是否打印,它都会为下一个过渡做好准备。紧接在
balance = total
之后, 添加 lastbalance = balance;
.这将保持当前账户的最新余额,以便在转换时打印。与帐号和名称不同,这必须针对每笔交易而不是每个账户进行。这是因为帐户/名称不会更改帐户,但期末余额会更改(对于每笔交易)。
在循环之外,紧接在
fclose (cfPtr2);
之前,放上代码:if (lastaccount != -1)
printf(" %-10d%-10s%.2lf\n", lastaccount, lastname, lastbalance);
这将打印最终帐户的详细信息,假设有任何已处理。如前所述,这是必需的,因为由于帐号更改,您将到达文件末尾而无需进行转换。
并且,作为最终要求,请:
conio.h
并使用 getchar()
而不是 getch()
. gcc
- 好多了:-) fflush(stdin)
. int main (void) ...
. main
返回一些东西(尽管我认为这在标准的后续版本中有所放松)。 我不会发布我的实际代码(除非您保证它不是家庭作业),但以下成绩单显示这些更改应该足以解决您当前的问题:
$ cat clients.dat
1 Pax 4.2
2 Roger 0
$ cat transactions.dat
1 1/2/3 112.3
1 2/3/4 -22.1
2 3/4/5 7
$ ./qq
Account Name Balance
|----------------------------------|
1 Pax 94.40
2 Roger 7.00
对于它的值(value),我不确定我是否完全同意将交易文件视为主要元素。由于您的工作是复制需要修改的帐户文件(如交易文件中指定的那样),因此我更愿意将帐户文件作为主要单位进行处理。
这样对我来说似乎更干净。
而且,为了完整起见,这是我想出的代码。我不建议将此作为作业提交,因为有很多事情可能会降低你的分数,这些事情在现实世界中的重要性要小得多,但教育 worker 在他们的帽子里有一个特别的蜜蜂:-) 像多个返回点,使用
#define
而不是 enum
, 等等。#include <stdio.h>
#include <string.h>
#define HDR_LINE 0
#define HDR_FULL 1
static void outHeader (int withHeading) {
printf ("+-%-6s-+-%-10s-+-%-6s-+-%-6s-+-%-6s-+\n",
"------", "----------", "------", "------", "------");
if (withHeading)
printf ("| %-6s | %-10s | %-6s | %-6s | %-6s |\n",
" Acct ", " Name ", " Date ", "Amount", "Balnce");
}
static void closeFiles (FILE *pfCli, FILE *pfTxn, FILE *pfNew) {
if (pfCli) fclose (pfCli);
if (pfTxn) fclose (pfTxn);
if (pfNew) fclose (pfNew);
}
static int openFiles (FILE **pfCli, FILE **pfTxn, FILE **pfNew) {
*pfCli = *pfTxn = *pfNew = NULL;
if ((*pfCli = fopen ("clients.dat", "r")) == NULL) {
printf ("File clients.dat could not be opened\n");
closeFiles (*pfCli, *pfTxn, *pfNew);
return 0;
}
if ((*pfTxn = fopen ("transactions.dat", "r")) == NULL) {
printf ("File transactions.dat could not be opened\n");
closeFiles (*pfCli, *pfTxn, *pfNew);
return 0;
}
if ((*pfNew = fopen ("clientupdate.dat", "w")) == NULL) {
printf ("File clientupdate.dat could not be opened\n");
closeFiles (*pfCli, *pfTxn, *pfNew);
return 0;
}
return 1;
}
static void outCli (int acct, char *nm, double bal, char *ind) {
if (acct == -1)
printf ("| %6s | %-10s | %6s | %6s | %6.2lf | %s\n",
"", nm, "", "", bal, ind);
else
printf ("| %6d | %-10s | %6s | %6s | %6.2lf | %s\n",
acct, nm, "", "", bal, ind);
}
static void outTxn (char *date, double amt, double bal) {
printf ("| %6s | %10s | %-6s | %6.2lf | %6.2lf |\n",
"", "", date, amt, bal);
}
static void getTxn (FILE *fh, int *acct, char *date, double *amt) {
if (feof (fh))
*acct = -1;
else
fscanf (fh, "%d%s%lf\n", acct, date, amt);
}
static void getCli (FILE *fh, int *last, int *acct, char *nm, double *bal) {
if (*last != -1)
outCli (-1, "", *bal, "-->");
*last = *acct;
fscanf (fh, "%d%s%lf\n", acct, nm, bal);
}
int main (void) {
int cli_acct, txn_acct, last_acct = -1;
char txn_date[10], cli_nm[10];
double cli_bal, txn_amt;
FILE *fCli, *fTxn, *fNew;
// Open all files, output header and load up first transaction.
if (!openFiles (&fCli, &fTxn, &fNew))
return 1;
outHeader (HDR_FULL);
getTxn (fTxn, &txn_acct, txn_date, &txn_amt);
// Process every account.
while (!feof (fCli)) {
// Bring in an account and print starting balance.
getCli (fCli, &last_acct, &cli_acct, cli_nm, &cli_bal);
outHeader (HDR_LINE);
outCli (cli_acct, cli_nm, cli_bal, "<--");
// While account is not yet up to txn, output and read new.
while (cli_acct < txn_acct) {
fprintf (fNew, "%d %s %.2lf\n", cli_acct, cli_nm, cli_bal);
outCli (-1, "", cli_bal, "-->");
outHeader (HDR_LINE);
fscanf (fCli, "%d%s%lf\n", &cli_acct, &cli_nm, &cli_bal);
outCli (cli_acct, cli_nm, cli_bal, "<--");
}
// If they don't match, you have a orphan transaction.
if ((cli_acct != txn_acct) && (txn_acct != -1)) {
printf ("Orphan transaction for account # %d\n", txn_acct);
closeFiles (fCli, fTxn, fNew);
return 1;
}
// While account and transaction match, process transaction lines.
while (cli_acct == txn_acct) {
cli_bal = cli_bal + txn_amt;
outTxn (txn_date, txn_amt, cli_bal);
if (feof (fTxn))
txn_acct = -1;
else
fscanf (fTxn, "%d%s%lf\n", &txn_acct, &txn_date, &txn_amt);
}
fprintf (fNew, "%d %s %.2lf\n", cli_acct, cli_nm, cli_bal);
}
// Output final lines if needed.
if (last_acct != -1)
outCli (-1, "", cli_bal, "-->");
outHeader (HDR_LINE);
// Close all files and exit successfully.
closeFiles (fCli, fTxn, fNew);
return 0;
}
鉴于
clients.dat
的:0 Mary 99.9
1 Pax 4.2
2 Bob 7
4 Roger 0
5 Nobody 9
和
transactions.dat
的:1 1/2/3 112.3
1 2/3/4 -22.1
4 3/4/5 7
这输出:
+--------+------------+--------+--------+--------+
| Acct | Name | Date | Amount | Balnce |
+--------+------------+--------+--------+--------+
| 0 | Mary | | | 99.90 | <--
| | | | | 99.90 | -->
+--------+------------+--------+--------+--------+
| 1 | Pax | | | 4.20 | <--
| | | 1/2/3 | 112.30 | 116.50 |
| | | 2/3/4 | -22.10 | 94.40 |
| | | | | 94.40 | -->
+--------+------------+--------+--------+--------+
| 2 | Bob | | | 7.00 | <--
| | | | | 7.00 | -->
+--------+------------+--------+--------+--------+
| 4 | Roger | | | 0.00 | <--
| | | 3/4/5 | 7.00 | 7.00 |
| | | | | 7.00 | -->
+--------+------------+--------+--------+--------+
| 5 | Nobody | | | 9.00 | <--
| | | | | 9.00 | -->
+--------+------------+--------+--------+--------+
并创建
clientupdate.dat
的:0 Mary 99.90
1 Pax 94.40
2 Bob 7.00
4 Roger 7.00
5 Nobody 9.00
随意将该代码用于任何目的,而不是将其作为您自己的作业。
关于C 文件处理和匹配帮助,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4940874/