2020寒假课设(分享下设计思路和TC2.0上古编译器踩的坑)

项目:一卡通消费记录管理系统

一、 功能需求说明(必须采用结构体和动态链表实现)
【1】消费记录存在文件fee.txt中,格式如下:
每一条记录包括一个消费的交易日期、入账日期、交易额、交易后余额、交易类型、交易次数、交易地点。示例如下
【2】查询搜索功能
(1)用户能够查询自己的一卡通固定时段消费情况:可以按月、学期、学年查询
(2) 用户可以自定义一个时间段进行查询自己的消费情况
(3)用户可以按交易金额查找消费记录
(4)管理员可查询任一用户的消费记录,可按照固定时段、自定义时段、金额方式、已删除记录查询
【3】排序功能:按消费记录的交易日期、金额、次数中一个进行(升序或降序)排序。
【4】数据录入:管理员能录入某个用户的一卡通消费情况,可以一次完成若干条记录的输入。【5】显示功能:可进行全部消费记录的显示,也可按照查询结果进行显示。
【6】数据变更:管理员可以更改或删除用户的某条消费记录,但删除的信息要保存在另外一个文件fee_undel.dat。
【7】统计功能:
(1)用户可统计自己在一个自定义时间段里的消费总金额情况。
(2)管理员可统计各个用户在一个自定义时间段里的消费总金额情况。
【8】用户和管理员的权限要分开。
另外需要应提供一个界面来调用各个功能,调用界面和各个功能的操作界面应尽可能清晰美观。

经历感受

1、由于是第一次写项目,要打出那么冗杂的代码并且调试对我来说难度还是很大的,刚开始最困难的就是怎么去构建一个大框架来实现不同函数的功能,比如如何将文件里用户的数据跟自己设计的系统联系起来等。
2、回想一下写代码的时间大概用了两天多吧,其实在dev上调试效率还是挺高的,不过因为写代码的时候粗心,指针用错把数组的地址改了,而且那个地方很难发现折腾一下午才意外发现,调试的时候还遇到了很多问题,数组开小,排序时返回的头地址不对,结束条件不恰当等我都被卡了很久。虽然遇到的问题多,但是收获不少,调试能力提升了很多。
3、这次课设最难的是用TC2.0这种祖师爷编译器来运行,还要在里面生成图形库来提供一个界面来调用各个功能,最无语的是TC是不能使用中文的,硬是把dev里面写好的代码的输出语句中的中文全部翻译成英文。在把dev里面调试好的代码搬到tc运行,结果在录入数据这一步就卡住了,运行不了,把高级编译器里能成功运行的代码搬到tc上运行没想到还有那么多问题,用了整整一天才改好。
4、最后在tc里面设计界面,收获挺大,学到了很多图形设计的函数,最坑的是怎么生成图形库,你可能因为电脑不兼容根本不能在终端那里生成obj目标文件,查了网上的资料,基本都是那几步,但就是生成不了,原因是tc是32位的,Win10系统是不能运行的,后来才想到在tc的dos shell窗口操作,调用initgraph()函数前还要加上registerbgidriver(EGAVGA_driver);语句才能生成图形库。

##踩坑后总结的tc2.0图形库生成的步骤:
1、打开tc2.0,在dos shell窗口下进行。
2、在C:\TC子目录下输入命令:BGIOBJ EGAVGA。
(此命令将驱动程序EGAVGA.BGI转换成EGAVGA.OBJ的目标文件。)
3、将OBJ文件剪切到C:\TC子目录中。
4、在C:\TC子目录下输入命令:TLIB LIB\GRAPHICS.LIB+EGAVGA
(此命令的意思是将EGAVGA.OBJ的目标模块装到GRAPHICS.LIB库文件中。)
5、在程序中initgraph()函数调用之前加上一句: registerbgidriver(EGAVGA_driver);
(该函数告诉连接程序在连接时把EGAVGA的驱动程序装入到用户的执行程序中。)

TC2.0一卡通消费记录系统运行界面

1、建立了8个文档,分别是三个用户的消费记录数据和删除记录数据,另外两个文档保存用户的用户名和密码和管理员的账号和密码。
2、进入登录界面
在这里插入图片描述
录入用户和管理员的用户名和密码,在登录的时候区分出身份。
3、主菜单
在这里插入图片描述
1是查询消费记录,2是排序功能,3是统计一个时间段的总消费金额,4是录入用户数据(需录入用户的消费记录数据才能进行1,2,3,5的功能),5是删除更新功能。
4、查询功能菜单
在这里插入图片描述
5、查询已删除的记录
在这里插入图片描述
6、删除界面
在这里插入图片描述
7、统计界面
在这里插入图片描述
还有其他界面就不一 一上传了。

以下是没加界面在DEV上运行的代码

//注:个人编写,请勿抄袭

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include <windows.h>
#define LEN sizeof(struct node)
char user_name[3][20],user_password[3][20];
char boss_name[20],boss_password[20];
char name[20],password[20];int i1,t,m,f=0;//t,m为用户编号的标记,f 
struct node
{
 long int deal_date,in_date;int times;//交易日期,入账日期,交易次数
 float money,remain;//交易金额,交易后余额 
 char type[20],place[20];//交易类型,交易地点
 struct node *next; 
};
//------------------------------------------------------------------------------------------// 
void Printf_node(struct node *head);void update_data(struct node *head);
void Fprintf(FILE*fp,struct node *head1);int Count_data(struct node *head);
struct node *read_data();struct node *read_delete_data();void gotoxy(int x,int y);
struct node *delete_node_function(struct node *head,struct node *head1);
int judge_boss();int judge_user();int login();int menu();
int search_function(struct node *head,struct node *head1);int search_menu1();int search_menu();
struct node *sort_function(struct node *head);int sort_menu(); 
//以上为各函数声明 
void main()
{  
 struct node *head=NULL,*head1=NULL;int num1,num2,num3=1;
 login();if(t==-1)exit(0);
 system("cls"); 
 while(1)
 { 
   num1=menu();
   switch(num1)
   {
   case 1:
    search_function(head,head1);break;
   case 2:
     head=sort_function(head);
     if(f==0)Printf_node(head);
     else system("cls");
     break;
   case 3:
     Count_data(head);break; 
   case 4:
     head=read_data();
     head1=read_delete_data();
     printf("数据录入成功!");break; 
   case 5:
     if(head==NULL){printf("消费记录为空,未录入数据");break;} 
     printf("消费记录为:\n"); 
     Printf_node(head);
     while(num3)
     {
     head=delete_node_function(head,head1);
      printf("继续删除?输入1继续、输入0结束:");
      scanf("%d",&num3);
      head1=read_delete_data(); 
     }
     update_data(head);break;
   case 0:
     exit (0);break;
   }
 } 
} 
void gotoxy(int x,int y)//x为列坐标,y为行坐标
{
COORD pos = {x,y};
HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE);
SetConsoleCursorPosition(hOut, pos);
}
int login()
{
  int judge_boss();
  int judge_user(); 
  FILE*fp;int j;
  fp=fopen("D:\\一卡通\\user.txt","r");//文件路径可自行更改
  for(i1=0;i1<3;i1++)fscanf(fp,"%s%s",&user_name[i1],&user_password[i1]);
  fp=fopen("D:\\一卡通\\boss.txt","r");
  fscanf(fp,"%s%s",boss_name,boss_password);fclose(fp); 
  for(j=0;j<5;j++)
  { 
    printf("|-------------------------------|\n");
    printf("|用户名:                       |\n");
    printf("|-------------------------------|\n");
    printf("|密码  :                       |\n");
    printf("|-------------------------------|\n");
    gotoxy(8,1); 
    scanf("%s",name);
    gotoxy(8,3);
    scanf("%s",password);
    if(judge_boss()&&judge_user())
    {
     printf("用户名或密码错误,你还有%d次机会\n",4-j);
     memset(name,'\0',sizeof(name));//重置name
     memset(password,'\0',sizeof(password));//重置password
    }
    if(judge_boss()==0)
    {printf("登录成功,欢迎管理员\n");t=0;return t;break;}
    if(judge_user()==0) 
    {printf("登录成功,欢迎用户\n");t=i1+1;return t;break;}
  }
 t=-1;return t;
}//登录后可验证身份,用户编号为1、2、3,管理员编号为0,登陆失败后编号为-1。
int judge_boss()//该函数判断是否为管理员身份 
{
  if((!strcmp(name,boss_name))&&(!strcmp(password,boss_password)))
  return 0;
  return 1;
}
int judge_user()//该函数判断是否为用户身份 
{ 
  int flag;
  for(i1=0;i1<3;i1++)
  {
  if(strcmp(name,user_name[i1])&&strcmp(password,user_password[i1]))
  flag=1;
  else{flag=0;break;
  }
 }
 return flag; 
}
int menu()//主菜单 
{
  int num;
  printf("---------------------------------------------------------------\n");
  printf("***************************************************************\n");
  printf("1---查询   2---排序   3---统计   4---录入   5---更新   0---退出\n");
  printf("***************************************************************\n");
  printf("---------------------------------------------------------------\n");
  while(1) 
  {
   printf("请输入想要执行的功能(数字):");
   scanf("%d",&num);
   if(num<6&&num>=0){system("cls");return num;}
   printf("输出错误!\n");
  }
}
int search_menu()//查询菜单 
{ 
  int num;
  printf("---------------------------------------------------------------\n");
  printf("***************************************************************\n");
  printf("  1--按固定时段查询       2--按日期区间段查询                  \n");
  printf("  3--按交易金额查询       4--已删除记录查询(管理员才有此项功能)\n");
  printf("  0--返回上一层                                                \n"); 
  printf("***************************************************************\n");
  printf("---------------------------------------------------------------\n");
  while(1) 
  {
    printf("请输入想要执行的功能(数字):");
    scanf("%d",&num);
    if(num<5&&num>=0)return num;
    printf("输出错误!\n");
  }
}
int search_menu1()//固定时间段查询菜单 
{ 
  int num;
  printf("---------------------------------------------------------------\n");
  printf("***************************************************************\n");
  printf("  1---------------按年查询           2---------------按月查询  \n");
  printf("  3---------------按日查询           0---------------返回上一层\n");
  printf("***************************************************************\n");
  printf("---------------------------------------------------------------\n");
  while(1) 
  {
   printf("请输入想要执行的功能(数字):");
   scanf("%d",&num);
   if(num<4&&num>=0)return num;
   printf("输出错误!\n");
  }
} 
int search_function(struct node *head,struct node *head1)//该函数实现查询功能 
{
  void Printf_node(struct node *head);
  struct node *p;int year,month,day,k=0,num1,num2;
  long int date1,date2;float money1;
  p=head;
  if(p==NULL){printf("消费记录为空,未录入数据");return 0;}//如果头指针为空指针则未录入数据 
  while(1)
  {
  num1=search_menu();if(num1==0){system("cls");return 0;}
  if(num1==1){system("cls");num2=search_menu1();}
  if(num2!=0)break;
  else system("cls");
  }
  switch(num1)
  {
   case 1:
     switch(num2)
     {
      case 1:printf("请输入要查询的年份:");scanf("%d",&year);system("cls");printf("消费记录:\n");break;
      case 2:printf("请输入要查询的月份:");scanf("%d",&month);system("cls");printf("消费记录:\n");break;
      case 3:printf("请输入要查询的日份:");scanf("%d",&day);system("cls");printf("消费记录:\n");break; 
     }break;
   case 2:
     printf("请输入日期区间段,格式为 始-末:");
     while(1)
     {
      scanf("%ld-%ld",&date1,&date2);
      if(date1<10000000||date2<10000000){printf("输入格式错误");continue;}
      break;
     }
     system("cls");printf("消费记录:\n");break;
   case 3:
     printf("请输入要查询的交易金额:");
     scanf("%f",&money1);system("cls");printf("消费记录:\n");break;
   case 4://管理员专业功能,查看用户删除的消费记录 
     if(t!=0)
     {k=1;
     printf("-----------------------");
     printf("非管理员无法使用此功能!");break;
     }
     else
     {k=1;system("cls");printf("消费记录有:\n");Printf_node(head1);break;} 
  }
 while(p)
 {
  switch(num1)
  {
    case 1://按固定时段查询 
     switch(num2)
     {
      case 1://按年查询 
        if(p->deal_date/10000==year)
        {k=1;
        printf("%ld\t%ld\t%7.2f\t%7.2f\t%s\t%d\t%s\n",p->deal_date,p->in_date,p->money,p->remain,p->type,p->times,p->place);
        }
        break;  
      case 2://按月查询 
        if((p->deal_date/100)%100==month)
        {k=1;
        printf("%ld\t%ld\t%7.2f\t%7.2f\t%s\t%d\t%s\n",p->deal_date,p->in_date,p->money,p->remain,p->type,p->times,p->place);
        }
        break;
      case 3://按日查询 
        if(p->deal_date%100==day)
        {k=1;
        printf("%ld\t%ld\t%7.2f\t%7.2f\t%s\t%d\t%s\n",p->deal_date,p->in_date,p->money,p->remain,p->type,p->times,p->place);
        }
        break;
      }
      break;
    case 2://按自定义时段查询 
      if(p->deal_date>=date1&&p->deal_date<=date2)
      {k=1,printf("%ld\t%ld\t%7.2f\t%7.2f\t%s\t%d\t%s\n",p->deal_date,p->in_date,p->money,p->remain,p->type,p->times,p->place);}
      break;
    case 3://按消费金额查询 
      if(p->money==money1)
      {k=1,printf("%ld\t%ld\t%7.2f\t%7.2f\t%s\t%d\t%s\n",p->deal_date,p->in_date,p->money,p->remain,p->type,p->times,p->place);}
      break;
  }
  p=p->next;
 }
  if(k==0){printf("----------------\n");printf("无此消费记录\n");}return 0; 
 }
 int sort_menu()//排序菜单 
{
  int num;
  printf("---------------------------------------------------------------\n");
  printf("***************************************************************\n");
  printf("  1---------------交易日期           2---------------交易金额  \n");
  printf("  3---------------交易次数           0---------------返回上一层\n");
  printf("***************************************************************\n");
  printf("---------------------------------------------------------------\n");
  while(1) 
  {
   printf("请输入想要执行的功能(数字):");
   scanf("%d",&num);
   if(num<4&&num>=0)return num;
   printf("输出错误!\n");
  }
}
struct node *sort_function(struct node *head)//该函数实现排序功能 
{
  int sort_menu();
  int num;float a,b;
  struct node *p1=head,*pre1,*p2,*pre2,*pm;
  if(p1==NULL){printf("消费记录为空,未录入数据");return head;} 
  num=sort_menu();
  for(p1=head; p1->next; p1=p1->next)
     {
         for(p2=p1->next; p2; p2=p2->next)
         {   
         switch(num)
        {
      case 1:
        a=(float)p1->deal_date;
        b=(float)p2->deal_date;
        break;
      case 2:
        a=p1->money;
        b=p2->money;
        break;
      case 3:
        a=(float)p1->times;
        b=(float)p2->times;
        break;
      case 0:
        f=1;
        return head;
    }
     for(pre1=head; pre1; pre1=pre1->next)
                if(pre1->next==p1)break;//寻找p1的前驱结点 
            for(pre2=head; pre2; pre2=pre2->next)
                if(pre2->next==p2)break;//寻找p2的前驱结点 
             if(p1==head)
             {
                 if(p1->next==p2&&a>b)
                 {
                    p1->next=p2->next;
                    p2->next=p1;
                     pm=p2;
                   p2=p1;
                   p1=pm;
                     head=p1;
                 }
                 else if(a>b)
                 {
                    pm=p1->next;
                     p1->next=p2->next;
                     pre2->next=p1;
                     p2->next=pm;
                     pm=p2;
                     p2=p1;
                     p1=pm;
                     head=p1;
                 }
             }
             else
             {
                 if(p1->next==p2&&a>b)
                 {
                     p1->next=p2->next;
                     pre1->next=p2;
                     p2->next=p1;
                     pm=p1;
                     p1=p2;
                     p2=pm;
                }
                else if(a>b)
                {
                    pm=p1->next;
                    p1->next=p2->next;
                    pre2->next=p1;
                    p2->next=pm;
                    pre1->next=p2;
                    pm=p1;
                    p1=p2;
                    p2=pm;
                }
            }
        }
    }
    system("cls");
    printf("排序成功!消费记录为:\n");
    return head;
}
int Count_data(struct node *head)//该函数实现统计功能 
{
  long int a,b;
  float total=0.0;//total为总消费金额 
  struct node *p=head;
  if(p==NULL){printf("消费记录为空,未录入数据");return 0;} 
  printf("请输入时间段,格式为:始-末:");
  while(1)
  {
   scanf("%ld-%ld",&a,&b);
   if(a>b){printf("输出错误!");}
   if(a<=b)break;
  }
  while(p)
  {
    if(p->deal_date>=a&&p->deal_date<=b)
    total=total+p->money;
    p=p->next;
  }
  printf("该段时间总消费金额为:%7.2f元",total); 
}
struct node *read_data()//该函数实现录入消费记录 
{
  struct node *head,*p1,*p2;int n=0;FILE *fp;
  char filename[50],p[50],s[]={"_fee.txt"},s1[]={"D:\\一卡通\\"};//文件路径可自行更改 
  if(t==1||t==2||t==3)//判断是否为用户,再打开该用户的消费记录文件 
  {
   strcpy(p,&user_name[t-1][0]);
   strcpy(filename,strcat(s1,strcat(p,s)));
  }
  if(t==0)//判断是否为管理员,再打开需要录入的用户的消费记录文件
  {
    printf("你为管理员,请输入你选择录入的用户编号:");
    scanf("%d",&m);strcpy(p,&user_name[m-1][0]);
    strcpy(filename,strcat(s1,strcat(p,s)));
  } 
  fp=fopen(filename,"r");
  head=NULL;
  p1=p2=(struct node *)malloc(LEN);
  fscanf(fp,"%ld %ld %f %f %s %d %s",&p1->deal_date,&p1->in_date,&p1->money,&p1->remain,p1->type,&p1->times,p1->place);
  while(p1->deal_date!=0)
  {
   n++;
   if(n==1)head=p1;
   else
   p2->next=p1;
   p2=p1;
   p1=(struct node *)malloc(LEN);
   fscanf(fp,"%ld %ld %f %f %s %d %s",&p1->deal_date,&p1->in_date,&p1->money,&p1->remain,p1->type,&p1->times,p1->place);
  }
   p2->next=NULL;fclose(fp);
   return head;
}
struct node *read_delete_data()//该函数实现录入删除的消费记录 
{
  struct node *head1,*p3,*p4;int n=0;FILE *fp1; 
  char filename[50],p[50],b[]={"_fee_del.txt"},b1[]={"D:\\一卡通\\"};//文件路径可自行更改
  if(t==1||t==2||t==3)//判断是否为用户,再打开该用户的消费记录文件 
  {
  strcpy(p,&user_name[t-1][0]);
  strcpy(filename,strcat(b1,strcat(p,b)));
  }
  if(t==0)//判断是否为管理员,再打开需要录入的用户的消费记录文件
  {
   strcpy(p,&user_name[m-1][0]);
   strcpy(filename,strcat(b1,strcat(p,b)));
  }
  fp1=fopen(filename,"r");
  head1=NULL;
  p3=p4=(struct node *)malloc(LEN);
  fscanf(fp1,"%ld %ld %f %f %s %d %s",&p3->deal_date,&p3->in_date,&p3->money,&p3->remain,p3->type,&p3->times,p3->place);
  while(p3->deal_date!=0)
  {
   n++;
   if(n==1)head1=p3;
   else
   p4->next=p3;
   p4=p3;
   p3=(struct node *)malloc(LEN);
   fscanf(fp1,"%ld %ld %f %f %s %d %s",&p3->deal_date,&p3->in_date,&p3->money,&p3->remain,p3->type,&p3->times,p3->place);
  }
  p4->next=NULL;fclose(fp1);
  return head1;
}
void Printf_node(struct node *head)//该函数可以输出单向链表 
{
  struct node *p;
  p=head;
  while(p)
  {
   printf("%ld\t%ld\t%7.2f\t%7.2f\t%s\t%d\t%s\n",p->deal_date,p->in_date,p->money,p->remain,p->type,p->times,p->place);
   p=p->next;
  }
}
void Fprintf_node(FILE *fp,struct node *head1)//该函数向文件输出单向链表
 { 
  struct node *p;
  p=head1;
  while(p)
  {
  fprintf(fp,"%ld\t%ld\t%7.2f\t%7.2f\t%s\t%d\t%s\n",p->deal_date,p->in_date,p->money,p->remain,p->type,p->times,p->place);
  p=p->next;
  }
}
struct node *delete_node_function(struct node *head,struct node *head1)//该函数实现删除更新功能 
{ 
 void Fprintf_node(FILE *fp,struct node *head1);
 struct node *pt=head,*p1=head1,*pre;
 long int a,b;float c,d;char e[20],g[20];int f;
 FILE *fp;
 char filename[50],p[50],a1[]={"_fee_del.txt"},s[]={"D:\\一卡通\\"};//文件路径可自行更改
 if(t==1||t==2||t==3)
 {
  strcpy(p,&user_name[t-1][0]);
  strcpy(filename,strcat(s,strcat(p,a1)));
 }
 if(t==0)
 {
   strcpy(p,&user_name[m-1][0]);
   strcpy(filename,strcat(s,strcat(p,a1)));
 }
 fp=fopen(filename,"w");
 printf("---------------------请输入你要删除的消费记录-------------------\n"); 
 printf("交易日期  入账日期  交易金额  交易后余额  交易类型  交易次数  交易地点\n");
 scanf("%ld%ld%f%f%s%d%s",&a,&b,&c,&d,e,&f,g);
 while(pt)
 { 
   if((head->deal_date==a)&&(head->in_date==b)&&(head->money==c)&&(head->remain==d)&&(head->times==f))
   {
    if((!strcmp(head->type,e))&&(!strcmp(head->place,g)))
    {
      head=head->next;free(pt);
      Fprintf_node(fp,head1); 
      fprintf(fp,"%ld\t%ld\t%7.2f\t%7.2f\t%s\t%d\t%s\n0",a,b,c,d,e,f,g);
      fclose(fp);
      return head;
     }
   }
   if((pt->deal_date==a)&&(pt->in_date==b)&&(pt->money==c)&&(pt->remain==d)&&(pt->times==f))
   {
     if((!strcmp(pt->type,e))&&(!strcmp(pt->place,g)))
     {
       for(pre=head;pre;pre=pre->next)
            if(pre->next==pt)break;
       pre->next=pt->next;free(pt);
       Fprintf_node(fp,head1);
       fprintf(fp,"%ld\t%ld\t%7.2f\t%7.2f\t%s\t%d\t%s\n0",a,b,c,d,e,f,g);
       fclose(fp);
       return head;
     }
   }
   pt=pt->next;
 }
 Fprintf_node(fp,head1);
 fprintf(fp,"0");
 system("cls");
 printf("无此消费记录!");fclose(fp); 
 return head; 
}
void update_data(struct node *head)//该函数实现更新功能 
{
  FILE *fp;struct node *p=head;
  char filename[50],p1[50],a[]={"_fee.txt"},s[]={"D:\\一卡通\\"};//文件路径可自行更改
  if(t==1||t==2||t==3) 
  {
   strcpy(p1,&user_name[t-1][0]);
   strcpy(filename,strcat(s,strcat(p1,a)));
  }
  if(t==0)
  {
    strcpy(p1,&user_name[m-1][0]);
    strcpy(filename,strcat(s,strcat(p1,a)));
  }
  fp=fopen(filename,"w");
  while(p)
  {
    fprintf(fp,"%ld\t%ld\t%7.2f\t%7.2f\t%s\t%d\t%s\n",p->deal_date,p->in_date,p->money,p->remain,p->type,p->times,p->place); 
    p=p->next;
  }
  fprintf(fp,"0");fclose(fp); 
  printf("数据更新成功!"); 
}
发布了1 篇原创文章 · 获赞 3 · 访问量 110

猜你喜欢

转载自blog.csdn.net/weixin_45457922/article/details/104117015