通过链表实现信息管理系统(无error 无warning可存档)
一般来说,实现信息管理有两条路可以走,一种是通过数组来实现,另一种就是通过链表来实现。
相对于数组,链表使程序的运行效率更高,用到了C语言的精华所在——指针。
而这次我用链表做的这个信息系统是员工管理系统,实际上可以编写更多的管理系统,比如航班信息管理、超市信息管理以及最具有标志性的学生成绩信息管理等等。
用链表写信息管理系统的关键在于理解链表的结构。明白从磁盘读出数据本质上是再构建一个链表,把读出来的数据逐一插入到链表中从而实现读出文件。写入到磁盘上就比较简单,通过指针指向头结点,使指针不断指向下一个结点并输出数据到磁盘即可。
话不多说,上代码咯~
首先是菜单函数,这里边包含8个可用功能,如下所示:
void menu(void)
{
printf("=======================================\n");
printf("=======================================\n");
printf("===========员工信息管理系统============\n");
printf("=======================================\n");
printf("===========1.插入员工信息==============\n");
printf("=======================================\n");
printf("===========2.删除员工信息==============\n");
printf("=======================================\n");
printf("===========3.查询员工信息==============\n");
printf("=======================================\n");
printf("===========4.更新员工信息==============\n");
printf("=======================================\n");
printf("===========5.显示员工信息==============\n");
printf("=======================================\n");
printf("===========6.更改登录密码==============\n");
printf("=======================================\n");
printf("===========7.查看登录时长==============\n");
printf("=======================================\n");
printf("===========8.退出当前系统==============\n");
printf("=======================================\n");
printf("=======================================\n");
}
这里没什么可说的,接下来是结构体的构造以及各种函数的声明:
#include<stdio.h>
#include<stdlib.h>
#include<windows.h>
#include<time.h>
#include<string.h>
typedef struct Employee
{
int num; //工号
char name[32]; //姓名
char sex[10]; //性别
int age; //年龄
int salary; //工资
char address[32]; //住址
char state[32]; //工作状态
struct Employee*next; //next指针
}E,*Em;
void Insert(Em *head);
void Delete(Em *head);
void Search(Em head);
void Update(Em head);
void Show(Em head);
void menu(void);
void filein(Em *head);
void fileout(Em head);
这里边含有8个成员,除去链表中必备的next指针还有7个成员,实际上可以更多,大家可以自由发挥。
然后是插入函数、删除函数: 我在这里添加了每次插入就自动排序的功能,也就是按照员工的工号由小到大来进行排序。
void Insert(Em *head)
{
Em p0,p1,p2;
p1=p2=*head;
p0=(Em)malloc(sizeof(E));
printf("请输入员工工号:\n");
scanf("%d",&p0->num);
printf("请输入员工姓名:\n");
scanf("%s",p0->name);
printf("请输入员工性别:\n");
scanf("%s",p0->sex);
printf("请输入员工年龄:\n");
scanf("%d",&p0->age);
printf("请输入员工工资:\n");
scanf("%d",&p0->salary);
printf("请输入员工住址:\n");
scanf("%s",p0->address);
printf("请输入员工状态:\n");
scanf("%s",p0->state);
if(p0==NULL)
{
printf("申请空间失败\n");
return;
}
if(p1==NULL)
{
*head=p0;
p0->next=NULL;
}
else
{
while(p0->num>p1->num&&p1->next!=NULL) //按工号由小到大进行排序
{
p2=p1;
p1=p1->next;
}
if(p0->num<=p1->num)
{
if(p1==*head)
{
*head=p0;
p0->next=p1;
}
else
{
p2->next=p0;
p0->next=p1;
}
}
else
{
p1->next=p0;
p0->next=NULL;
}
}
printf("员工信息创建完成...\n");
}
void Delete(Em *head)
{
Em p1,p2;
int number;
p1=p2=*head;
printf("请输入要删除的员工工号:\n");
scanf("%d",&number);
if(*head==NULL)
{
printf("当前无员工信息,无法删除\n");
return;
}
else
{
while(p1->num!=number&&p1->next!=NULL)
{
p2=p1;
p1=p1->next;
}
if(p1->num==number)
{
if(p1==*head)
{
*head=p1->next;
}
else
{
p2->next=p1->next;
}
printf("已删除工号为%d的员工信息\n",number);
}
else
{
printf("没有找到拥有该工号的员工\n");
}
}
}
由于这里是void类型函数,所以要求在子函数中必须改变头指针的值,所以我们的传递的实参应该是头指针的地址,所以这里边相当于是一个二级指针,即通过改变指向头指针的指针的值来以此改变头指针的指向,这是需要注意的地方。所以我们的上传的实参应该是&head,形参应该是*head。
然后是查询、更新、显示函数: 这里用到的仍然是通过工号来进行相应的查询、更新、显示,但是实际上,通过输入员工的姓名、工资甚至是住址都可以进行如下功能,并且删除函数里也可以根据姓名来进行删除,在这里就是进行一个标志性地按工号执行以下函数( •̀ ω •́ )✧
void Search(Em head)
{
int flag=1;
int number;
Em p=head;
printf("请输入要查询的员工工号:\n");
scanf("%d",&number);
while(p!=NULL&&flag)
{
if(p->num==number)
{
printf("员工信息如下:\n");
printf("员工工号:%d\n",p->num);
printf("员工姓名:%s\n",p->name);
printf("员工性别:%s\n",p->sex);
printf("员工年龄:%d\n",p->age);
printf("员工工资:%d\n",p->salary);
printf("员工住址:%s\n",p->address);
printf("员工状态:%s\n",p->state);
printf("==========================\n");
flag=0;
}
p=p->next;
}
if(flag)
{
printf("没有找到拥有该工号的员工\n");
}
}
void Update(Em head)
{
int number,flag=1;
Em p0=head;
printf("请输入要更新的员工工号:\n");
scanf("%d",&number);
while(p0!=NULL&&flag)
{
if(number==p0->num)
{
printf("请输入员工工号:\n");
scanf("%d",&p0->num);
printf("请输入员工姓名:\n");
scanf("%s",p0->name);
printf("请输入员工性别:\n");
scanf("%s",p0->sex);
printf("请输入员工年龄:\n");
scanf("%d",&p0->age);
printf("请输入员工工资:\n");
scanf("%d",&p0->salary);
printf("请输入员工住址:\n");
scanf("%s",p0->address);
printf("请输入员工状态:\n");
scanf("%s",p0->state);
flag=0;
}
p0=p0->next;
}
if(flag)
{
printf("没有找到拥有此工号的员工\n");
}
}
void Show(Em head)
{
Em p=head;
while(p!=NULL)
{
printf("员工信息如下:\n");
printf("员工工号:%d\n",p->num);
printf("员工姓名:%s\n",p->name);
printf("员工性别:%s\n",p->sex);
printf("员工年龄:%d\n",p->age);
printf("员工工资:%d\n",p->salary);
printf("员工住址:%s\n",p->address);
printf("员工状态:%s\n",p->state);
printf("==========================\n");
p=p->next;
}
}
这里没什么值得强调的地方( •̀ ω •́ )✧
然后就是我们的重点,文件的读出和写入,这里边的读出是重新构造一个链表,地址和上一个链表的地址可以说几乎完全不同但也不能否定会有重合的地方,主要是把数据存到这个新链表中再被我们读出来进入到程序中,而且对于文件的打开方式一定注意要使用正确的形式,具体文件打开的方式在这里我就不进行赘述了,另外需要指出的是通过fwrite fread函数也可以进行读出和写入但是不如fscanf fprintf函数方便:
void filein(Em *head)
{
FILE*fp;
Em p,p0;
p=*head;
if((fp=fopen("emp.dat","r"))==NULL)
{
return;
}
while(1)
{
p0=(Em)malloc(sizeof(E));
p0->next=NULL;
if(p0==NULL)
{
printf("申请空间失败\n");
return;
}
if(fscanf(fp,"%d %s %s %d %d %s %s",&p0->num,p0->name,p0->sex,&p0->age,&p0->salary,p0->address,p0->state)!=7) //一共七项数据全部要读出来
{
break;
}
if(*head==NULL)
{
*head=p=p0;
}
else
{
p->next=p0;
p=p0;
}
}
free(p0);
p0=NULL;
fclose(fp);
}
void fileout(Em head)
{
FILE*fp;
Em p=head;
if((fp=fopen("emp.dat","w"))==NULL)
{
printf("打开文件失败\n");
exit(0);
}
while(p!=NULL)
{
fprintf(fp,"%d %s %s %d %d %s %s\n",p->num,p->name,p->sex,p->age,p->salary,p->address,p->state);
p=p->next;
}
fclose(fp);
}
最后就是我们的main函数。这里需要注意的点就是关于改写密码,由于最开始的时候文件都不存在,就要在最开始的时候初始化一个字符串然后赋给密码的字符数组,同时不要忘了再次读取密码的时候是已经更改好的密码啦。另外我又设定了新密码与旧密码不能一致以及开启程序三次密码输入错误就要关闭系统的功能,大家可以看看。
int main(void)
{
FILE*fp;
int j=0,start,end;
char choice,c;
char password[20];
char key[20];
char old[20],new[20];
if((fp=fopen("password","r"))==NULL)
{
strcpy(password,"12345678");
}
else
{
fscanf(fp,"%s",password);
}
fclose(fp);
while(j<3)
{
printf("请输入登录密码:\n");
scanf("%s",key);
if(strcmp(key,password)==0)
{
printf("匹配成功,正在登录...\n");
Sleep(1000);
break;
}
else
{
printf("匹配失败,请尝试再次输入\n");
j++;
continue;
}
}
if(j==3)
{
printf("已经输错了三次密码,即将退出系统...\n");
Sleep(1200);
exit(0);
}
printf("正在读取数据......\n");
Sleep(1000);
system("color 3");
printf("已就绪...\n");
system("pause&&cls");
start=clock();
Em head=NULL;
filein(&head);
while(1)
{
system("cls");
menu();
printf("请输入你的选择:\n");
scanf(" %c",&choice);
switch(choice)
{
case '1':
{
Insert(&head);
break;
}
case '2':
{
Delete(&head);
}
case '3':
{
Search(head);
break;
}
case '4':
{
Update(head);
break;
}
case '5':
{
Show(head);
break;
}
case '6':
{
char temp[20];
system("cls");
while(1)
{
printf("请输入原始密码:\n");
scanf("%s",old);
if(strcmp(old,password)==0)
{
printf("匹配成功,请设置你的新密码:\n");
t:
scanf("%s",new);
if(strcmp(new,old)==0)
{
printf("新密码不能与原始密码相同,请重新输入\n");
goto t;
}
else
{
strcpy(temp,new);
strcpy(new,password);
strcpy(password,temp);
printf("密码修改成功!\n");
break;
}
}
else
{
printf("匹配失败,是否继续修改密码?(Y/N)\n");
scanf(" %c",&c);
if(c=='n'||c=='N')
{
break;
}
}
}
break;
}
case '7':
{
end=clock();
printf("你已登录%d秒...\n",(end-start)/1000);
break;
}
case '8':
{
printf("正在退出系统...\n");
Sleep(1000);
goto j;
}
}
system("pause");
}
j:
printf("是否对当前信息进行存储?(Y/N)\n");
scanf(" %c",&c);
if(c=='y'||c=='Y')
{
if((fp=fopen("password","w"))==NULL)
{
printf("cannot open this file.\n");
exit(0);
}
fprintf(fp,"%s",password);
fclose(fp);
fileout(head);
printf("正在存储......\n");
Sleep(800);
printf("已就绪...\n");
system("pause");
}
return 0;
}
好了,到这里就彻底结束了。整个程序运行起来没有任何问题,同时-Wall也没任何问题,关闭程序也可顺利读取文件并实现再次存入。如果有问题的话还请大佬帮忙指正呀~o( ̄▽ ̄)ブ