阅读下列“资金账户的管理”程序,对程序进行调试、改错,并增加函数,使之符合如下具体功能。
1) 资金账户的信息统一放在*随机文件中,该随机文件包括的数据项有记录ID、发生日期、发生事件、发生金额(正的表示收入,负的表示支出)和金额。每发生一笔收支,文件要增加一条记录,并计算一次余额。
2) 程序实现3个功能,包括:
(1) 能创建资金账户文件并添加收入或支出信息记录
(2) 能显示所有记录,得知资金账户的收支流水账;
(3) 能查询最后一条记录,获知账户最后的余额。
账户文件名命名为cashbox.dat,文件部分内容如下;
cashbox.dat
LongID CreateDateNote Charge Balance
1 2006-06-01 alimony 500.00 500.00
2 2006-06-08 shopping -300.00 200.00
3 2006-06-15 shopping -60.00 140.00
4 2006-06-20 workingpay 200.00 340.00
5 2006-08-01 scholarship 1000.00 1340.00
2) 增加修改资金账户的功能。输入一个记录ID,如果文件中已存在该记录,则输入新的记录信息并更新资金账户文件中相应记录的信息。
要求定义和调用函数UpdateLog(),其功能是修改资金账户记录。
3) 增加删除资金账户的功能。输入一个记录ID,如果文件中已存在该记录,则删除该记录信息。
要求定义和调用函数Deletelog(),其功能是删除资金账户记录。
随机读写是按你给的地点读写,(用 fseek 等函数找地点),可以在文件的任何地方–开始处,文件尾,文件中部,前前后后地读写。顺序读写 是从文件开始处依次读,从文件尾开始依次写。
对文件的读写操作可按指定的字节号进行。即可以通过调用库函数去指定开始读或写的字节号,然后直接对该位置上的数据进行读或写操作。
“b”是二进制模式//
if((fp=fopen(“cashbox.dat”,“ab+”))==NULL){
"a+"模式:
打开文件进行“读写”操作,即既可读取,又可写入
若欲操作的文件不存在,则新建文件
成功打开文件时,文件指针位于文件结尾
打开文件后,不会清空文件内原有内容
读取内容时,可以在任意位置进行,但写入内容时,只会追加在文件尾部
fp1=fopen(“cashbox.dat”,“wb+”);
"w+"模式:
1.打开文件进行“读写”操作,即既可读取,又可写入。
2.若欲操作的文件不存在,则新建文件。
3.成功打开文件时,文件指针位于文件开头。
4.打开文件后,会清空文件内原有的内容。
5.无论是读取内容还是写入内容,都可在文件中任意位置进行,且进行写入操作时,会覆盖原有位置的内容。
fseek函数设置文件指针cfp的位置(从SEEK_SET开始移动size*(logcount-1))
(0L不移动)SEEK_SET文件头 SEEK_END文件尾
ftell用于得到文件位置指针当前位置相对于文件首的偏移字节数
rewind(cfp);//重设文件指针
fread(&log,size,1,cfp); /1.读取到的位置指针 2.一个对象的字节大小 3.对象个数 4.要读的目标指针/
fwrite(plog,size,logcount,cfp);
#include <stdio.h>
#include <stdlib.h>
#include <process.h>
#include <string.h>
#include <conio.h>
long size;
/*当前最近一次的流水号*/
struct LogData{ /*记录的结构*/
long logid; /*记录ID*/
char logdate[11]; /*记录发生日期*/
char lognote[15]; /*记录事件说明*/
double charge; /*发生费用:负表示支出,正表示收入*/
double balance; /*余额*/
};
int inputchoice()/*选择操作参数*/
{
system("cls");
int mychoice;
printf("\n");
printf("\n");
printf(" 程序设计与实践 实验(二) 个人资金账户管理\n");
printf("\n");
printf(" Personal Cashbox Management\n");
printf(" ============================= \n");
printf(" 1 - Add a new cash log.\n 2 - List all cash log.\n");
printf(" 3 - Query last cash log.\n 4 - Update a cash log.\n");
printf(" 5 - Delete a cash log.\n 0 - End program.\n");
printf("\n");
printf(" Enter your choice:");
scanf("%d",&mychoice);
return mychoice;
}
long getLogcount(FILE *cfp) /*获取文件记录总数*/
{
long begin,end,logcount;
fseek(cfp,0L,SEEK_SET); //SEEK_SET文件头
begin=ftell(cfp); //ftell用于得到文件位置指针当前位置相对于文件首的偏移字节数
fseek(cfp,size,SEEK_END); //SEEK_END文件尾
end=ftell(cfp);
logcount=(end-begin)/size -1;
return logcount;
}
void AddNewLog(FILE *cfp) /*添加新记录*/
{
struct LogData log,lastlog;
long logcount;
printf("Input logdate(format:2020-01-01):");
scanf("%s",log.logdate);
printf("Input lognote:");
scanf("%s",log.lognote);
printf("Input Charge:Income+ and expend-:");
scanf("%lf",&log.charge);
logcount=getLogcount(cfp); /*获取记录数*/
if(logcount>0){
fseek(cfp,size*(logcount-1),SEEK_SET); /*fseek函数设置文件指针cfp的位置(从SEEK_SET开始移动size*(logcount-1))*/
fread(&lastlog,size,1,cfp); /*读入最后记录*/
log.logid=lastlog.logid+1; /*记录号按顺序是上次的号+1*/
log.balance=log.charge+lastlog.balance;
}
else{ /*如果文件是初始,记录数为0*/
log.logid=1;
log.balance=log.charge;
}
rewind(cfp);//重设文件指针
getch(); //等待按下任意键,再继续执行下面的语句
fwrite(&log,sizeof(struct LogData),1,cfp); /*写入记录*/
fclose(cfp);
}
void ListAllLog(FILE *cfp) /*列出所有收支流水帐*/
{
struct LogData log;
long logcount;
logcount=getLogcount(cfp);
if(logcount>0){ /*表示有记录存在*/
fseek(cfp,0L,SEEK_SET); /*定位指针到文件开始位置,0L—不移动*/
fread(&log,size,1,cfp); /*1.读取到的位置指针 2.一个对象的字节大小 3.对象个数 4.要读的目标指针*/
printf("LogID LogDate LogNote Charge Balance\n");
while(!feof(cfp)){ //检测文件结束符,如果文件结束,则返回非0值,否则返回0
printf("%5ld %-12s %-15s %10.2lf %10.2lf\n",
log.logid,log.logdate,log.lognote,log.charge,log.balance);
fread(&log,size,1,cfp);
}
}
else printf("no logs in file!\n");
printf("\n");
printf("Press any key to continue...");
system("pause");
}
void QueryLastLog(FILE *cfp) /*查询显示最后一条记录*/
{
struct LogData log;
long logcount;
logcount=getLogcount(cfp);
if(logcount>0){ /*表示有记录存在*/
fseek(cfp,size*(logcount-1),SEEK_SET); /*定位最后一条记录*/
fread(&log,size,1,cfp); /*读取最后一条记录*/
printf("The last log is:\n"); /*显示最后一条记录*/
printf(" LogID:%-6ld\n LogDate:%-11s\n LogNote:%-15s\n",
log.logid,log.logdate,log.lognote);
printf(" Charge:%-10.2lf\n *Balance:%-10.2lf\n",
log.charge,log.balance);
}
else printf("no logs in file!\n");
printf("\n");
printf("Press any key to continue...");
getch();
}
/*函数功能:查询记录 ID 并更新账户记录*/
void Updatelog(FILE *cfp){
struct LogData log[1000],*plog=log,newlog; /*假定文件不超过1000记录*/
//plog=log数组首地址?
long logcount,logid,i,index=-1;
printf("Input LogID:");
scanf("%ld",&logid); /*输入要修改的记录 ID*/
/*查找帐户号是否存在,若存在则更新*/
logcount=getLogcount(cfp); /*获取记录数*/
rewind(cfp);
fread(plog,size,logcount,cfp); //相当于copy?从文件中读到数组中
for(i=0;i<logcount;i++){
if(logid==log[i].logid){ /*已经找到*/
printf("LogID LogDate LogNote Charge Balance\n");/*显示当前记录*/
printf("%5ld %-12s %-15s %10.2lf %10.2lf\n",
log[i].logid,log[i].logdate,log[i].lognote,log[i].charge,log[i].balance);
index=i;
break;
}
}
rewind(cfp);
if(index>=0){
printf("Input logdate(format:2020-01-01):");
scanf("%s",newlog.logdate);
printf("Input lognote:");
scanf("%s",newlog.lognote);
printf("Input Charge:Income+ and expend-:");
scanf("%lf",&newlog.charge);
if(strcmp(log[index].lognote,newlog.lognote)!=0)//比较,如果不相同,则修改
strcpy(log[index].lognote,newlog.lognote);
if(strcmp(log[index].logdate,newlog.logdate)!=0)
strcpy(log[index].logdate,newlog.logdate);
/*如果输入的收支额度改变,重新计算余额*/
if(newlog.charge!=log[index].charge){
newlog.balance=log[index].balance-log[index].charge+newlog.charge; /*计算新余额*/
log[index].charge=newlog.charge; /*更新收支*/
log[index].balance=newlog.balance; /*更新余额*/
/*当前记录之后的每条记录余额信息更新*/
for(i=index+1;i<logcount;i++)
log[i].balance=log[i-1].balance+log[i].charge;
}
rewind(cfp);
fwrite(plog,size,logcount,cfp); /*更新回文件*/
}
else{
printf("Error logid and try another!\n");
printf("Press any key to continue...");
getch();
}
fclose(cfp);
}
/*函数功能:查询记录 ID 并删除该账户记录*/
void Deletelog(FILE *cfp){
FILE *fp1;
struct LogData log[1000],*plog=log;/*假定文件不超过 1000 记录*/
long logcount,logid,i,index=-1;
printf("Input LogID:");
scanf("%ld",&logid); /*输入要删除的记录 ID*/
/*查找帐户号是否存在,若存在则更新*/
logcount=getLogcount(cfp); /*获取记录数*/
rewind(cfp);
fread(plog,size,logcount,cfp); //从文件中读到数组中
for(i=0;i<logcount;i++){
if(logid==log[i].logid){ /*已经找到,显示当前记录*/
printf("LogID LogDate LogNote Charge Balance\n");
printf("%5ld %-12s %-15s %10.2lf %10.2lf\n",
log[i].logid,log[i].logdate,log[i].lognote,log[i].charge,log[i].balance);
index=i;
getch();
break;
}
}
printf("\n");
rewind(cfp);
if(index>=0){
for(i=index;i<=logcount-1;i++){ //将index之后的数据整体前移
log[i].logid=i+1;
strcpy(log[i].logdate,log[i+1].logdate);
strcpy(log[i].lognote,log[i+1].lognote);
log[i].charge=log[i+1].charge;
log[i].balance=log[i-1].balance+log[i].charge;
}
printf("Now\n");
printf("LogID LogDate LogNote Charge Balance\n");
for(i=0;i<logcount-1;i++){ /*输出当前new记录*/
printf("%5ld %-12s %-15s %10.2lf %10.2lf\n",
log[i].logid,log[i].logdate,log[i].lognote,log[i].charge,log[i].balance);
}
getch();
fp1=fopen("cashbox.dat","wb+");
//打开文件后,会清空文件内原有的内容。
/*
"w+"模式:
1.打开文件进行“读写”操作,即既可读取,又可写入。
2.若欲操作的文件不存在,则新建文件。
3.成功打开文件时,文件指针位于文件开头。
4.打开文件后,会清空文件内原有的内容。
5.无论是读取内容还是写入内容,都可在文件中任意位置进行,且进行写入操作时,会覆盖原有位置的内容。
"b"表示二进制;
*/
fwrite(plog,size,logcount-1,fp1);/*写回去更新*/
fclose(fp1);
}
else{
printf("Error logid and try another!\n");
printf("Press any key to continue...");
getch();
}
}
int main(void)
{
FILE *fp;
int choice;
if((fp=fopen("cashbox.dat","ab+"))==NULL){
//打开文件后,不会清空文件内原有内容
/*
"a+"模式:
打开文件进行“读写”操作,即既可读取,又可写入
若欲操作的文件不存在,则新建文件
成功打开文件时,文件指针位于文件结尾
打开文件后,不会清空文件内原有内容
读取内容时,可以在任意位置进行,但写入内容时,只会追加在文件尾部
"b"表示二进制;
*/
printf("can not open file cashbox.dat!\n");
exit(0);//退出程序
}
size=sizeof(struct LogData);//一个结构体所占的字节—52?
while((choice=inputchoice())!=0){
switch(choice){
case 1:
fp=fopen("cashbox.dat", "ab+");
AddNewLog(fp);break;/*添加新记录*/
case 2:
fp=fopen("cashbox.dat", "ab+");
ListAllLog(fp);break;/*列出所有的收入支出情况*/
case 3:
fp=fopen("cashbox.dat", "ab+");
QueryLastLog(fp);break;/*查询最后的余额*/
case 4:
fp=fopen("cashbox.dat", "rb+");
Updatelog(fp);break;/*新增语句更新资金账户记录*/
case 5:
fp=fopen("cashbox.dat", "rb+");
Deletelog(fp);break;/*删除一条资金账户记录*/
default:
printf("Input Error.");break;
}
}
if(fclose(fp)){//如果关闭成功返回 0,否则返回EOF(-1)
printf( "Can not close the file!\n" );
exit(0);//退出程序
}
}