刚刚进入大二,准备开始学习C++,对大一所学的C语言一次练习,正好也是赶上老师布置的任务,用C语言写一个 销售管理系统 ,就尽可能的把所学的都用上,也就是结构,指针,文件操作,还有数据结构,本次加入了链表。
用两个函数 Load_LinkList() 和 Save_LinkList() 让链表与文件操作结合,除了打印函数,其他都是在内存中操作链表,这样写更有条理,在创建链表时没有采用书上的用一个中间变量引导,并插入到结点前面,而是直接在链表尾的next申请内存,便于理解,操作也方便。
/*首先是文件包含,这里就不使用 ifndef 那样常规写一个头文件*/ #include <stdio.h> #include <string.h> #include <windows.h> #include <stdlib.h> #include <conio.h>
/*接下来就是结构体*/ /*每一种商品对应一个结点,用链表连接起来,统一写入文件,或者从文件中读取*/ typedef struct commodity { int data; //头结点data统计个数,其余为商品编号 char name[20]; //名称 double price; //价格 int count; //数量 double sum; //总计,头结点sum为所有商品总计 struct commodity *next; } *LinkList, LNode;
/*定义全局变量,方便使用*/ /*链表头指针*/ LinkList H = NULL; /*文件指针*/ FILE *fp = NULL;
/*函数声明*/ /***************显示函数****************/ //欢迎界面 void welcome(); //显示菜单 void menu();
//打印表格头 void printf_header();
//显示单个结点信息 void printf_linklist_info(LinkList pTemp); //延时函数 void delay(); /***********链表文件操作函数*****************/ //从文件中读取到链表中 void Load_LinkList(LinkList H); //将链表保存到文件中 void Save_LinkList(LinkList H); /***************链表函数**********************/ //建立头结点 void Creat_LinkList(); //添加结点到链表尾部 LinkList Add_LinkList(LinkList H); //输入结点数据 void Scanf_LinkList(LinkList pTemp); //找到符合要求的结点的前驱 LinkList Find_LinkList_Pos(LinkList H,int index); //找到符合要求的结点的地址 LinkList Find_LinkList_Val(LinkList H, char *name); //删除指定结点 void Del_LinkList(LinkList H, char *name); //修改结点内容 void Modify_LinkList(LinkList H, int index, int data); //顺序输出 void Printf_LinkList(LinkList H); //释放内存 void Free_LinkList(LinkList H);
/*main函数,没什么说的,除了getch函数用的时候会方便一些*/ int main() { LinkList pTemp = NULL; char name[20] = {0}; system("color A"); //welcome(); Creat_LinkList(); Load_LinkList(H); while(1) { system("cls"); menu(); switch(getch()) { case '1': pTemp = Add_LinkList(H); Scanf_LinkList(pTemp); getch(); break; case '2': printf_header(); Printf_LinkList(H); getch(); break; case '3': printf("\n输入名称查找:"); scanf("%s", name); pTemp = Find_LinkList_Val(H, name); printf_linklist_info(pTemp); getch(); break; case '4': printf("\n请先输入名称查找:"); scanf("%s", name); pTemp = Find_LinkList_Val(H, name); Scanf_LinkList(pTemp); getch(); break; case '5': printf("\n请先输入名称查找:"); scanf("%s", name); Del_LinkList(H, name); getch(); break; case '6': Save_LinkList(H); printf("\n成功保存%d条信息!\n", H->data); getch(); break; case '0': printf("\n欢迎下次使用!\n"); exit(0); default : printf("错误输入!"); getch(); } } return 0; }
下面是显示函数实现内容
/*欢迎界面,其实不要也可以*/ void welcome() { int i; for(i=1 ; i<=100 ; i++) { printf("*******************欢迎使用本系统*************************"); printf("\n\n\n\n\n\n\n"); printf(" 加载中"); printf("...\n"); printf(" %3d%%\n",i); printf("**********************************************************"); system("cls"); } return ; }
/*菜单函数*/ void menu() { system("cls"); printf(" 欢迎进入本系统 \n"); printf("\n"); printf("-------------------------------------------------------------------\n"); printf("| 1 添加商品 |\n"); printf("| 2 显示商品 |\n"); printf("| 3 查找商品 |\n"); printf("| 4 修改商品 |\n"); printf("| 5 删除商品 |\n"); printf("| 6 保存修改 |\n"); printf("| 0 退出系统 |\n"); printf("-------------------------------------------------------------------\n"); printf(" 提示:退出前请先保存!"); printf("\nchoose(0-8):"); }
/*以表格的形式打印所有商品信息*/ void printf_header() { system("cls"); printf("-------------------------您的所有库存-------------------------------------\n"); printf("| 编号 | 名称 | 价格 | 数量 | 总计 |\n"); printf("|----------|---------------|---------------|----------------|------------|\n"); }
/*显示单个结点信息*/ void printf_linklist_info(LinkList pTemp) { if(pTemp == NULL) { return ; } printf_header(); pTemp->sum = pTemp->price * pTemp->count; printf("|%10d|%15s| %lf |%20d| %lf |\n",pTemp->data, pTemp->name, pTemp->price, pTemp->count, pTemp->sum); printf("|----------|---------------|---------------|----------------|------------|\n"); return ; }
/*延时函数,写完了发现我一直用的是getch等待按键*/ void delay() { long int i,j; for(i=500000 ; i>0 ; i--) { for(j=0 ; j<=2000 ; j++); } }
/*创建头结点*/ void Creat_LinkList() { H = (LinkList)malloc(sizeof(LNode)); if(H) { H->next = NULL; H->data = 0; } return ; }
/*添加结点,这里是直接用最后一个节点的next申请内存*/ LinkList Add_LinkList(LinkList H) { LinkList q = H; while(q->next != NULL) q = q->next; q->next = (LinkList)malloc(sizeof(LNode)); q->next->sum = 0; q->next->next = NULL; H->data++; return q->next; }
/*用于添加结点时输入结点信息,或者修改时输入*/ void Scanf_LinkList(LinkList pTemp) { if(pTemp == NULL) { return ; } printf("\n输入编号:"); scanf("%d", &pTemp->data); printf("输入名称:"); scanf("%s", pTemp->name); printf("输入价格:"); scanf("%lf", &pTemp->price); printf("输入数量:"); scanf("%d", &pTemp->count); pTemp->sum = pTemp->price * pTemp->count; }
/*从文件中读取并加载到链表中,和Save函数一样,是最关键的两个函数*/ void Load_LinkList(LinkList H) { LinkList p = NULL, pTemp = NULL; pTemp = (LinkList)malloc(sizeof(LNode)); pTemp->next = NULL; fp = fopen("D:/a.txt", "rb"); while(1) { /*这里用一个中间结点,临时储存,fread读一次才能决定是否添加结点,直接用p添加结点会错误,本身就是空文件时会多出一个结点,存的垃圾值,而fread必须有一块内存才能读*/ if((fread(pTemp, sizeof(LNode), 1, fp)) != 0) { p = Add_LinkList(H); p->data = pTemp->data; strcpy(p->name, pTemp->name); p->price = pTemp->price; p->count = pTemp->count; } else break; } free(pTemp); fclose(fp); return ; }
/*将链表保存到文件中*/ void Save_LinkList(LinkList H) { LinkList p = H->next; if(p == NULL) { /*这里是清空一下,假如链表中保存的有数据,调用删除完之后,不能用fwrite,只是这种情况下用wb清空文件*/ fp = fopen("D:/a.txt", "wb"); H->data = 0; fclose(fp); getch(); return ; } fp = fopen("D:/a.txt", "wb"); while(p != NULL) { fwrite(p, sizeof(LNode), 1, fp); p = p->next; } fclose(fp); return ; }
///接下来的函数就是只在内存里面操作链表
/*通过位置查找,返回结点 前驱结点 地址,计划是有这个查找的,后来写菜单也不想用了,就放这里没动过*/ LinkList Find_LinkList_Pos(LinkList H,int index) { LinkList p = H; index--; while(index--) { p = p->next; } return p; }
/*通过字符串匹配查找,返回结点地址*/ LinkList Find_LinkList_Val(LinkList H, char *name) { LinkList p = H; while(strcmp(p->name, name) != 0 && p->next != NULL) { p = p->next; } if(p->next == NULL && strcmp(p->name, name) != 0) { printf("没有此商品!"); return NULL; getch(); } return p; }
/*删除一个结点,pre是前驱结点,p是要找的结点*/ void Del_LinkList(LinkList H, char *name) { int flag = 0; LinkList p = H->next, pre = H; while(p != NULL) { if(strcmp(p->name, name) == 0) { flag = 1; break; } pre = p; p = p->next; } if(flag == 0) { printf("没有此商品!\n"); return ; } p = pre->next; pre->next = p->next; free(p); return ; }
/*修改结点信息,也是也可以实现的,和Find_LinkList_Pos()一样,没有用过*/ void Modify_LinkList(LinkList H, int index, int data) { LinkList p = Find_LinkList_Pos(H, index+1); if(p) p->data = data; return ; }
/*顺序输出,表格没有对太齐,应该用 %xd 这样的,后来也不想改了*/ void Printf_LinkList(LinkList H) { LinkList p = NULL; p = H->next; if(p == NULL) { printf("当前没有任何商品!"); getch(); return ; } while(p != NULL) { p->sum = p->price * p->count; printf("|%10d|%15s| %lf | %15d | %lf |\n",p->data, p->name, p->price, p->count, p->sum); printf("-------------------------------------------------------------------------------\n"); p = p->next; } printf(" %lf\n", H->sum); return ; }
/*内存总是要释放的*/ void Free_LinkList(LinkList H) { LinkList pre = NULL, p = H; while(p != NULL) { pre = p->next; free(p); p = pre; } H = NULL; return ; }