首先看一张自制的设计框架:
我个人觉得在设计c语言信息管理系统中,基本都是以上的框架
例如:
1、学生信息管理系统
2、酒店客房管理系统
3、火车售票管理系统
4、职工信息管理系统
5、图书信息管理系统
这类系统,无非就是把数据从磁盘中拿出来,再对数据秀一番操作后,又写入到磁盘中,整体这样去看待就简单多了
类似以上的系统,都可以套用下面的模板进行自行修改使用其中主要难点:
1、结构体数组、结构体链表
2、标准文件I/O操作
3、程序设计的熟练
接下来上代码:
//编译环境:Dev c++编译器 (不同的编译器可能有细微的差别,可自行改动调试)
//编译语言:C
//数据结构:结构体、单链表
//可以套用大多数的信息管理系统
//框架与设计介绍:
//1、登录模块
//2、功能子模块
//3、主菜单调用
//其中可扩展部分在框内自行添加,无需改动的会标注
#include<stdio.h>
struct Information
{
char name[20]; //姓名
char number[20];//编号
int age; //年龄
//**自行添加**
struct Information *next;//连接下一个节点
};
const unsigned char allchar[63] = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";//随机产生字符串使用
char Str[10];//随机产生字符串使用
///////////////////////////////////////// 1、登陆模块 //////////////////////////////////////////
void Verification() //随机产生字符串
{
int i=6;
srand((unsigned int)time(NULL));
while(i--)
{
Str[5-i]=allchar[rand()%62];
}
Str[5]='\0';
}
void Validation(char account[],char password[]) //函数用于验证账号密码的正确性
{
char s_account[20],s_password[20],s_verification[10];
while(1){
printf("请输入账户:");
scanf("%s",&s_account);
printf("请输入密码:");
scanf("%s",&s_password);
Verification(); //调用函数产生验证码
printf("请输入验证码(%s):",Str);
scanf("%s",&s_verification);
if((strcmp(s_account,account)==NULL)&&(strcmp(s_password,password)==NULL)) //如果账户和密码正确
{
if((strcmp(Str,s_verification)==NULL))
{
printf("登陆成功!\n");
break;
}
printf("验证码错误!\n");
Sleep(2000);
system("cls");
continue;
}
printf("账户或密码验证失败!\n");
Sleep(2000);
system("cls");
}
}
void Landing() //函数用于从磁盘中读取账户和密码数据,并且传递给 Validation函数进行验证
{
//打开Landing.txt文件,读取账户和密码信息
char account[20]; //账号
char password[20]; //密码
char Verification[10]; //验证码
FILE *fp;
if((fp=fopen("Landing.txt","r"))==NULL)
{
printf("Landing.txt文件打开失败!\n");
exit(0);
}
fscanf(fp,"账号: %s 密码: %s\n",&account,&password);
fclose(fp);
Validation(account,password); //把磁盘中的账户和密码传入验证函数
}
//////////////////////////////////// 2、功能子模块 ////////////////////////////////////////
//**自行添加别的函数模块**
struct Information * Initialize(struct Information *head) //调用函数进行初始化(从磁盘文件中读取信息)
{
FILE *fp;
struct Information *p,*q; //head指向链表头,q和q来进行尾插法
p=q=NULL;
if((fp=fopen("data.txt","r"))==NULL)//判断文件是否正确打开
{
printf("file open fail !\n");
exit(0);
}
if(fgetc(fp)==EOF) //判断文件是否为空
{
printf("磁盘文件为空!\n");
return(head);
}
rewind(fp); //由于上面fgetc使文件位置指针移动,让其还原
head=q=p=(struct Information *)malloc(sizeof(struct Information)); //分配空间
//**fscanf按照结构体自行修改,不懂格式看链接:https://blog.csdn.net/qq_42856154/article/details/93225821 掌握文件I/O操作**
fscanf(fp,"姓名:%s 编号:%s 年龄:%d\n",p->name,p->number,&p->age); //已经判断文件有数据,读取第一个数据,作为头节点
while(!feof(fp)) //feof(fp):当返回值为1时,文件到达尾部当返回值为0时,文件未到达尾部
{
p=(struct Information *)malloc(sizeof(struct Information));
//**fscanf按照结构体自行修改
fscanf(fp,"姓名: %s 编号:%s 年龄: %d\n",p->name,p->number,&p->age); //格式读取信息,一次一行
q->next=p;
q=p;
}
p->next=NULL; //尾节点next域赋值为NULL
p=q=NULL; //指针指向为NULL
fclose(fp);
return(head); //返回链表的头指针
}
struct Information * Increase(struct Information *head) //增加节点(在链表尾增加)
{
struct Information *p,*q;
q=head;
p=(struct Information *)malloc(sizeof(struct Information));
//**按照自己定义的结构体自行修改
printf("请输入姓名:");
scanf("%s",p->name);
printf("请输入编号:");
scanf("%s",p->number);
printf("请输入年龄:");
scanf("%d",&p->age);
p->next=NULL;
if(head==NULL) //当头节点不存在时,把创建的节点直接当作头节点
{
head=p;
}
else
{
while(q->next!=NULL)
q=q->next;
q->next=p;
}
q=p=NULL;
printf("增加成功!\n");
return head;
}
struct Information * Delete(struct Information *head) //删除节点 (按编号删除)
{
int i=0;
char num[20];
struct Information *p,*q;
p=q=head;
printf("请输入要删除的编号:");
scanf("%s",num);
while(q!=NULL)
{
if(i>1)p=p->next;
i++;
if((strcmp(num,q->number)==NULL))
{
printf("已经找到是第 %d 个节点\n",i);
goto delete;
}
q=q->next;
}
printf("该编号信息不存在!\n");
return head;
delete:
if(i==1) //删除头节点
{
head=q->next;
printf("头节点删除成功!\n");
return head;
}
if(q->next==NULL) //删除尾节点
{
p->next=NULL;
p=q=NULL;
return head;
}
p->next=q->next; //删除中间节点
free(q);
q=NULL;
printf("删除成功!\n");
return head;
}
int Find(struct Information *head) //查找节点信息 (按编号查找)
{
int i=0;
char num[20];
printf("请输入要查找的编号:");
scanf("%s",num);
while(head!=NULL)
{
i++;
if((strcmp(num,head->number)==NULL))
{
printf("已经找到在: %d 个节点\n",i);
//**printf按照结构体自行修改
printf("姓名: %s 编号:%s 年龄: %d\n",head->name,head->number,head->age);
return 0;
}
head=head->next;
}
printf("该编号信息不存在!\n");
return 0;
}
int Change(struct Information *head) //修改节点信息 (按编号修改)
{
//该函数可以做成(按照名称、学好、编号查找,本例为编号查找),可以自行修改
char num[20];
printf("请输入要修改的编号:");
scanf("%s",num);
while(head!=NULL)
{
if((strcmp(num,head->number)==NULL))
{
printf("姓名: %s 编号:%s 年龄: %d\n",head->name,head->number,head->age);
printf("请输入除编号外的其它信息\n\n");
printf("请输入姓名:");
scanf("%s",head->name);
printf("请输入年龄:");
scanf("%d",&head->age);
printf("姓名: %s 编号:%s 年龄: %d\n",head->name,head->number,head->age);
printf("\n修改成功!\n");
return 0;
}
head=head->next;
}
printf("该编号信息不存在!\n");
return 0;
}
int Print_list(struct Information *head) //打印链表数据
{
if(head==NULL)
{
printf("链表为空!\n");
return 0;
}
while(head!=NULL) //当头指针不为NULL,表示头节点有数据
{
//**printf按照结构体自行修改
printf("姓名: %s 编号:%s 年龄: %d\n",head->name,head->number,head->age);
head=head->next;
}
return 0;
}
void Save(struct Information *head)
{
FILE *fp;
if((fp=fopen("data.txt","w"))==NULL)//判断文件是否正确打开
{
printf("file open fail !\n");
exit(0);
}
while(head!=NULL)
{
//**fprintf按照结构体自行修改
fprintf(fp,"姓名: %s 编号:%s 年龄: %d\n",head->name,head->number,head->age);
head=head->next;
}
printf("保存磁盘成功!\n");
fclose(fp);
}
/////////////////////////////////// 3、主菜单调用 ///////////////////////////////////////////
void Menu()
{
Sleep(2000);
system("cls");
//**按照函数功能自行修改菜单目录
printf("\t\t\t*****功能主菜单*****\n\n\n");
printf("\t\t*** 增加节点 ***\t\t--1\n");
printf("\t\t*** 删除节点 ***\t\t--2\n");
printf("\t\t*** 修改节点 ***\t\t--3\n");
printf("\t\t*** 查询节点 ***\t\t--4\n");
printf("\t\t*** 打印链表 ***\t\t--5\n");
printf("\t\t*** 保存磁盘 ***\t\t--6\n");
printf("\t\t*** 退出系统 ***\t\t--7\n");
}
int main()
{
//main函数内可能变化较大,所以根据自己的喜好进行排布代码
int flag = 1;
int n;
struct Information *Head = NULL; //头指针(头指针为空,只是用来指向头节点)
Landing(); //1、登陆模块调用,使用默认的账户和密码进行验证(**登陆**)
Head = Initialize(Head); //2、调用函数进行初始化(**从磁盘文件中读取信息恢复链表**)
while(flag)
{
Menu();
printf("请选择:");
scanf("%d",&n);
switch(n)
{
case 1:Head = Increase(Head);break;
case 2:Head = Delete(Head);break;
case 3:Change(Head);break;
case 4:Find(Head);break;
case 5:Print_list(Head);break;
case 6:Save(Head);break;
case 7:flag = 0;break;
default:printf("输入错误!\n");
}
}
return 0;
}
代码总体不长,但基本功能很完善,但严格来测试会存在数据BUG,但作为学习是可以的
做了一些这类程序,最大的感受就是:(先栽树,再去修剪枝干和美化叶子)
OK
代码大致介绍:
1、语言:C语言
2、数据结构:结构体链表作为整个代码的核心
3、文件操作:文本文件的格式化写入和读出操作
4、登陆模块:账户密码验证+随机验证码
5、功能子模块:
- 增加节点
- 删除节点
- 修改节点
- 查询节点
- 初始化从磁盘中读取数据初始化链表
- 向磁盘中保存整个链表(不追加,直接覆盖文件)
- 打印整条链表
(项目目录下里面有两个txt格式的文件,data.txt 和 Landing.txt)
data.txt:保存链表数据
Landing.txt:保存登陆账号和密码数据
在项目目录下建立这两个txt文件,data.txt中可以不存数据,但要存的话一定是这种格式,Landing.txt一定要保存图片中的内容
建议:
1、登陆模块分用户账号和管理员账号,对子函数功能操作时进行权限设置,可以增强整个程序
2、子模块可以添加一些数据统计类的模块
3、main函数中的设计中,应该不断改进调用的顺序,使代码看起来紧凑条理清晰,这一块的调用控制,决定着最后的运行效果和使用体验
就说这些,如果要拿去使用,建议具体跑一跑,再配合(注释)自行添加修改
最后附上一句鸡汤:绝知此事必躬行有什么问题,欢迎评论区里留言