用两个函数 Load_LinkList() 和 Save_LinkList() 让链表与文件操作结合,除了打印函数,其他都是在内存中操作链表,这样写更有条理,在创建链表时没有采用书上的用一个中间变量引导,并插入到结点前面,而是直接在链表尾的next申请内存,便于理解,操作也方便。
/*首先是文件包含,这里就不使用 ifndef 那样常规写一个头文件*/
#include
#include
#include
#include
#include
/*接下来就是结构体*/
/*每一种商品对应一个结点,用链表连接起来,统一写入文件,或者从文件中读取*/
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;
H->data++;
}
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)
{
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->next;
while(pre != NULL)
{
pre = p->next;
free(p);
p = p->next;
}
H->next = NULL;
return ;
}
/*首先是文件包含,这里就不使用 ifndef 那样常规写一个头文件*/
#include
#include
#include
#include
#include
/*接下来就是结构体*/
/*每一种商品对应一个结点,用链表连接起来,统一写入文件,或者从文件中读取*/
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;
H->data++;
}
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)
{
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->next;
while(pre != NULL)
{
pre = p->next;
free(p);
p = p->next;
}
H->next = NULL;
return ;
}