学生管理系统C语言实现
近期做了一个学生管理系统,巩固了下文件io的知识!虽然只是一个小项目,不管对项目开发的认识有了一个小的提升。下面贴出各部分工作的代码。在codeblocks上编译完美运行。
先上图,程序运行后的菜单界面:
有基本的增删改查功能,还多了排序和统计的辅助功能。
接下来分头文件和各个函数说明程序实现原理。
1.结构体头文件Studen.h(注意:头文件和.c文件不在同一个目录下,所以导入头文件时要使用绝对路径)
该头文件定义了学生结构体,日期结构体和成绩结构体。
#ifndef STUDENT_H_INCLUDED
#define STUDENT_H_INCLUDED
/*头文件定义*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <conio.h>
#include <dos.h>
#include <process.h>
#include "Define.h"
#include "Function.h"
/*结构体定义*/
//成绩结构体
struct Score
{
float C_score; //c语言成绩
float Database_score; //数据库成绩
}SCORE;
//生日结构体
struct Birth
{
int year;
int month;
int day;
}BIRTH;
//学生信息结构体
struct student
{
char sex[3]; //性别
int age; //年龄
char name[10]; //姓名
char tel[15]; //电话
char stu_no[5]; //学号
float sum; //成绩总和
float avg; //成绩平均值
struct Birth birth; //出生日期
struct Score score; //各项成绩
}STU[100];
#endif // STUDENT_H_INCLUDED
2.宏定义头文件Define.h
这个头文件定义了打印的输出格式,用一个变量代替一长串的输出格式,极大提高编程效率。注意各个变量的输出格式,例如整型的用%s输出,会造成不必要的错误。博主就在里面栽了跟头,都是很低级的错误。
#ifndef DEFINE_H_INCLUDED
#define DEFINE_H_INCLUDED
/*宏定义*/
#define LEN sizeof(struct student) //结构体大小
//输出格式
#define FORMAT "%-5s%-9s%-5s%-5d%-14s%-4d-%-2d-%-5d%-7.1f%-7.1f%-7.1f%-7.1f\n"
#define DATA STU[i].stu_no,STU[i].name,STU[i].sex,STU[i].age,STU[i].tel,STU[i].birth.year,STU[i].birth.month,STU[i].birth.day,\
STU[i].score.C_score,STU[i].score.Database_score,STU[i].sum,STU[i].avg
#endif // DEFINE_H_INCLUDED
3.函数实现头文件Function.h
这个头文件声明各个函数。
#ifndef FUNCTION_H_INCLUDED
#define FUNCTION_H_INCLUDED
//#include "Student.h"
/*函数声明*/
void In(); //输入学生信息
void Show(); //显示学生信息
void Order(); //排序
void Del(); //删除
void Modify(); //修改
void Menu(); //菜单
void Insert(); //插入
void Total(); //总数
void Seek(); //查找
#endif // FUNCTION_H_INCLUDED
接下来是.c文件的实现。再次注意包含的头文件的路径,因为不是在一个工程目录下。
1.主函数main.c
主函数的作用就是打印菜单和接收用户的选择,并跳转到相应函数的实现。
#include "../inc/Student.h"
#include "../inc/Function.h"
int main(void)
{
int n;
Menu();
scanf("%d",&n);
while(n)
{
switch(n)
{
case 1: In(); break;
case 2: Seek(); break;
case 3: Del(); break;
case 4: Modify(); break;
case 5: Insert(); break;
case 6: Order(); break;
case 7: Total(); break;
case 8: Show(); break;
default :break;
}
getch(); //会等待你按下任意键,再继续执行下面的语句;
Menu(); //执行完所选功能再次打印菜单
scanf("%d",&n);
}
//printf("Goodbye!\n");
printf("\n\t|------------------------感谢你的使用!-------------------------|\n");
return 0;
}
2.函数功能实现function.h
(1)包含需要的头文件:(再再次强调绝对路径)
#include "../inc/Student.h"
#include "../inc/Function.h"
#include "../inc/Define.h"
(2)菜单 void Menu()
只用来打印菜单
void Menu()
{
system("cls");
printf("\n\n\n\n");
printf("\t|-------------------------学生管理系统--------------------------|\n");
printf("\t| |\n");
printf("\t|\t\t\t 0.退出 |\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");
printf("\t|\t\t\t 8.显示学生信息 |\n");
printf("\t| |\n");
printf("\t| 作者:RongXiangXing 时间:2017/6/11 |\n");
printf("\t|---------------------------------------------------------------|\n");
printf("\t\t\t输入0-8选择相应的功能: ");
}
(3)输入学生信息函数 void In()
先到指定的文件中查看是否还有记录,如果没有记录,就打印没有记录的提示信息;有过有记录,就将已有记录显示出来。
void In() //输入学生信息函数
{
int i,m = 0; //m是记录行数
char ch[2];
FILE *fp; //定义文件指针
if((fp = fopen("Database.txt","a+")) == NULL)
{
printf("无法代开文件!\n");
return ;
}
while(!feof(fp)) //feof(fp)表示到达文件末尾
{
if(fread(&STU[m],LEN,1,fp) == 1) //若成功则返回实际读入的count数据,即1
m++; //记录条数增加
}
fclose(fp); //关闭文件
if( m == 0)
printf("没有记录!\n");
else
{
system("cls"); //清屏
Show();
}
if((fp = fopen("Database.txt","wb")) == NULL)
{
printf("无法代开文件!\n");
return ;
}
for(i = 0 ; i < m ; i++)
fwrite(&STU[i],LEN,1,fp); //向指定的磁盘文件写入信息
printf("是否输入学生信息(y/n):");
scanf("%s",ch);
while(strcmp(ch,"Y") == 0 || strcmp(ch,"y") == 0) //判断是否要输入信息
{
printf("学号:");
scanf("%s",STU[m].stu_no); //数组名就是首地址
for( i = 0 ; i < m ; i++)
{
if(STU[i].stu_no == STU[m].stu_no)
{
printf("该学号已存在,请重新输入或将已有学号信息删除再输入!");
getch();//会等待你按下任意键,再继续执行下面的语句;
fclose(fp);
return ;
}
}
printf("姓名:");
scanf("%s",STU[m].name); //输入姓名
printf("性别:");
scanf("%s",STU[m].sex); //输入性别,非数组要用取地址符&
printf("年龄:");
scanf("%d",&STU[m].age); //输入年龄
printf("电话:");
scanf("%s",STU[m].tel); //输入电话
printf("出生日期:");
scanf("%d%d%d",&STU[m].birth.year,&STU[m].birth.month,&STU[m].birth.day);//输入出生日期
printf("C语言成绩:");
scanf("%f",&STU[m].score.C_score);//输入C语言成绩
printf("数据库成绩:");
scanf("%f",&STU[m].score.Database_score);//输入数据库成绩
STU[m].sum = STU[m].score.C_score + STU[m].score.Database_score; //计算成绩总和
STU[m].avg = STU[m].sum / 2.0; //计算平均值
if(fwrite(&STU[m],LEN,1,fp) != 1)
{
printf("无法存储信息,请检查输入格式!");
getch();
}
else
{
printf("%s号学生信息已保存!\n",STU[m].stu_no);
m++; //记录增加
}
printf("是否继续录入信息?(y/n):");
scanf("%s",ch);
}
fclose(fp);
printf("输入操作完成,按任意键进入主菜单!\n");
}
运行界面:
(4)查询学生信息函数void Seek()
先按学号查询,如果没有找到,则提示使用姓名查询,若果仍没找到,打印提示信息。若找到则打印学生信息。
void Seek() //查询学生信息函数
{
FILE *fp;
char ch[2],snum[5],sname[10];
int i,m = 0;
if((fp = fopen("Database.txt","rb")) == NULL) //以只读方式打开文件
{
printf("无法代开文件!\n");
return ;
}
while(!feof(fp)) //feof(fp)表示到达文件末尾
{
if(fread(&STU[m],LEN,1,fp) == 1) //若成功则返回实际读入的count数据,即1
m++; //记录条数增加
}
fclose(fp);
if(m == 0)
{
printf("没有记录!\n");
return ;
}
printf("请输入要查询的学号:");
scanf("%s",snum);
for(i=0;i<m;i++)
{
if(strcmp(snum,STU[i].stu_no) == 0)
{
printf("学号 姓名 性别 年龄 电话 出生日期 C语言 数据库 sum avg\n");
printf(FORMAT,DATA); //若找到按指定格式输出信息
break;
}
}
if(i == m)
{
printf("没有找到这名学生的记录!\n");
printf("是否尝试进行姓名查找?(y/n):");
scanf("%s",ch);
for(i=0;i<m;i++)
{
if(strcmp(ch,"Y") == 0 || strcmp(ch,"y") == 0)
{
printf("请输入要查找学生的姓名:");
scanf("%s",sname);
if(strcmp(sname,STU[i].name) == 0)
{
printf("学号 姓名 性别 年龄 电话 出生日期 C语言 数据库 sum avg\n");
printf(FORMAT,DATA); //若找到按指定格式输出信息
break;
}
else
{
printf("仍然无法找到这名学生的记录!\n");
break;
}
}
}
}
printf("查询操作完成,按任意键进入主菜单!\n");
}
运行界面:
(5)删除学生信息函数 void Del()
如果找到学生信息,提示是否删除。没找到则打印没有该学生信息。
void Del() //删除学生信息函数
{
FILE *fp;
char ch[2],snum[5];
int i,j,m = 0;
if((fp = fopen("Database.txt","r+")) == NULL) //以可读写方式打开文件
{
printf("无法代开文件!\n");
return ;
}
while(!feof(fp)) //feof(fp)表示到达文件末尾
{
if(fread(&STU[m],LEN,1,fp) == 1) //若成功则返回实际读入的count数据,即1
m++; //记录条数增加
}
fclose(fp);
if(m == 0)
{
printf("没有记录!\n");
return ;
}
printf("请输入要删除记录的学生学号:");
scanf("%s",snum);
for(i=0;i<m;i++)
{
if(strcmp(snum,STU[i].stu_no) == 0) //如果找到这个学生的记录
break;
}
printf("学生记录已找到,是否确定删除?(y/n):");
scanf("%s",ch);
if(strcmp(ch,"Y") == 0 || strcmp(ch,"y") == 0)
{
for(j=i;j<m;j++)
{
STU[j] = STU[j+1]; //后面记录的信息往前移,删除该条记录
m--; //记录条数减少
}
}
if((fp = fopen("Database.txt","wb")) == NULL) //重新写入操作后的记录
{
printf("无法代开文件!\n");
return ;
}
for(j=0;j<m;j++)
{
if(fwrite(&STU[j],LEN,1,fp) != 1)
{
printf("写入信息失败!\n");
getch();
}
}
fclose(fp);
printf("删除操作完成,按任意键进入主菜单!\n");
}
运行界面:
(6)修改学生信息函数 void Modify()
若找到要修改的学生信息的记录,则提示修改的各项信息,若没有找到,则打印查无此人的信息。
void Modify() //修改学生信息函数
{
FILE *fp;
int i,j,m = 0;
char snum[5];
if((fp = fopen("Database.txt","r+")) == NULL) //以可读写方式打开文件
{
printf("无法代开文件!\n");
return ;
}
while(!feof(fp)) //feof(fp)表示到达文件末尾
{
if(fread(&STU[m],LEN,1,fp) == 1) //若成功则返回实际读入的count数据,即1
m++; //记录条数增加
}
fclose(fp);
Show();
printf("请输入你想要修改信息的学生学号:");
scanf("%s",snum);
for(i=0;i<m;i++)
{
if(strcmp(snum,STU[i].stu_no) == 0)
{
printf("找到该学生的记录,现在你能进行更新信息!\n");
printf("姓名:");
scanf("%s",STU[i].name); //输入姓名
printf("性别:");
scanf("%s",STU[i].sex); //输入性别,非数组要用取地址符&
printf("年龄:");
scanf("%d",&STU[i].age); //输入年龄
printf("电话:");
scanf("%s",STU[i].tel); //输入电话
printf("出生日期:");
scanf("%d%d%d",&STU[i].birth.year,&STU[i].birth.month,&STU[i].birth.day);//输入出生日期
printf("C语言成绩:");
scanf("%f",&STU[i].score.C_score);//输入C语言成绩
printf("数据库成绩:");
scanf("%f",&STU[i].score.Database_score);//输入数据库成绩
STU[i].sum = STU[i].score.C_score + STU[i].score.Database_score; //计算成绩总和
STU[i].avg = STU[i].sum / 2.0; //计算平均值
printf("学生信息修改成功!\n");
break;
}
}
if(i == m)
{
printf("没有找到该学生的记录!\n");
}
if((fp = fopen("Database.txt","wb")) == NULL) //重新写入操作后的记录
{
printf("无法代开文件!\n");
return ;
}
for(j=0;j<m;j++) //将修改后的信息重新写入磁盘文件
{
if(fwrite(&STU[j],LEN,1,fp) != 1)
{
printf("写入信息失败!\n");
getch();
}
}
fclose(fp);
printf("修改操作完成,按任意键进入主菜单!\n");
}
运行界面:
(7)插入学生信息函数
在要插入的学号的后面插入学生信息。
void Insert() //插入学生信息函数
{
FILE *fp;
int i,j,k,m = 0;
char snum[5];
if((fp = fopen("Database.txt","r+")) == NULL) //以可读写方式打开文件
{
printf("无法代开文件!\n");
return ;
}
while(!feof(fp)) //feof(fp)表示到达文件末尾
{
if(fread(&STU[m],LEN,1,fp) == 1) //若成功则返回实际读入的count数据,即1
m++; //记录条数增加
}
fclose(fp);
if(m == 0)
{
printf("没有记录!\n");
return ;
}
printf("请输入你想要插入的学号的位置(是在输入的学号后面插入):");
scanf("%s",snum);
for(i=0;i<m;i++)
{
if(strcmp(snum,STU[i].stu_no) == 0)
{
printf("找到要插入的学生的位置!现在你可以插入学生信息!\n");
for(j=m-1;j>i;j--)
{
STU[j+1] = STU[j]; //从最后一条记录开始向后移,为要插入的信息提供空间
}
printf("学号:");
scanf("%s",STU[i+1].stu_no); //数组名就是首地址
for(k=0 ; k<m ; k++)
{
if(STU[k].stu_no == STU[i+1].stu_no)
{
printf("该学号已存在,请重新输入或将已有学号信息删除再输入!");
getch();//会等待你按下任意键,再继续执行下面的语句;
fclose(fp);
return ;
}
}
printf("姓名:");
scanf("%s",STU[i+1].name); //输入姓名
printf("性别:");
scanf("%s",STU[i+1].sex); //输入性别,非数组要用取地址符&
printf("年龄:");
scanf("%d",&STU[i+1].age); //输入年龄
printf("电话:");
scanf("%s",STU[i+1].tel); //输入电话
printf("出生日期:");
scanf("%d%d%d",&STU[i+1].birth.year,&STU[i+1].birth.month,&STU[i+1].birth.day);//输入出生日期
printf("C语言成绩:");
scanf("%f",&STU[i+1].score.C_score);//输入C语言成绩
printf("数据库成绩:");
scanf("%f",&STU[i+1].score.Database_score);//输入数据库成绩
STU[i+1].sum = STU[i+1].score.C_score + STU[i+1].score.Database_score; //计算成绩总和
STU[i+1].avg = STU[m].sum / 2.0; //计算平均值
printf("成功插入学生信息!\n");
}
}
if((fp = fopen("Database.txt","wb")) == NULL) //重新写入操作后的记录
{
printf("无法代开文件!\n");
return ;
}
for(k=0;k<=m;k++) //将修改后的信息重新写入磁盘文件,因为插入后记录加1,所以这里是<=m
{
if(fwrite(&STU[k],LEN,1,fp) != 1)
{
printf("写入信息失败!\n");
getch();
}
}
fclose(fp);
printf("插入操作完成,按任意键进入主菜单!\n");
}
运行界面:
(8)按成绩总和排序学生信息void Order() (也可以自己尝试按单科成绩排名)
void Order() //排序学生信息
{
FILE *fp;
struct student t; //定义student结构体对象,用于交换记录
int i=0,j=0,m=0;
if((fp = fopen("Database.txt","r+")) == NULL) //以可读写方式打开文件
{
printf("无法代开文件!\n");
return ;
}
while(!feof(fp)) //feof(fp)表示到达文件末尾
{
if(fread(&STU[m],LEN,1,fp) == 1) //若成功则返回实际读入的count数据,即1
m++; //记录条数增加
}
fclose(fp);
if(m == 0)
{
printf("没有记录!\n");
return ;
}
if((fp = fopen("Database.txt","wb")) == NULL) //重新写入操作后的记录
{
printf("无法代开文件!\n");
return ;
}
for(i=0;i<m;i++) //使用冒泡排序法进行排序
{
for(j=0;j<m-i-1;j++)
{
if(STU[j].sum < STU[j+1].sum)
{
t = STU[j];
STU[j] = STU[j+1];
STU[j+1] = t;
}
}
}
if((fp = fopen("Database.txt","wb")) == NULL) //重新写入操作后的记录
{
printf("无法代开文件!\n");
return ;
}
for(i=0;i<m;i++) //将修改后的信息重新写入磁盘文件,因为插入后记录加1,所以这里是<=m
{
if(fwrite(&STU[i],LEN,1,fp) != 1)
{
printf("写入信息失败!\n");
getch();
}
}
fclose(fp);
printf("排序操作完成,按任意键进入主菜单后可按8显示功能查看!\n");
}
运行界面:
(8)求总人数函数void Total(),其实就是求出文件中的记录数
void Total() //求总人数
{
FILE *fp;
int m=0;
if((fp = fopen("Database.txt","r+")) == NULL) //以可读写方式打开文件
{
printf("无法代开文件!\n");
return ;
}
while(!feof(fp)) //feof(fp)表示到达文件末尾
{
if(fread(&STU[m],LEN,1,fp) == 1) //若成功则返回实际读入的count数据,即1
m++; //记录条数增加
}
fclose(fp);
if(m == 0)
{
printf("没有记录!\n");
return ;
}
Show();
printf("总共有 %d 名学生的信息!\n",m);
printf("按任意键进入主菜单!\n");
}
运行界面:(打印出的学生信息,就是上一步已排序好的信息)
(9)显示学生信息函数void Show()
将文件中所有的学生信息记录打印出来。
void Show() //显示已有记录
{
FILE *fp;
int i,m = 0;
fp = fopen("Database.txt","rb");//以只读方式打开二进制流文件,打开二进制文件是因为速度快
while(!feof(fp))
{
if(fread(&STU[m],LEN,1,fp) == 1)
m++;
}
fclose(fp);
printf("学号 姓名 性别 年龄 电话 出生日期 C语言 数据库 sum avg\n");
for(i = 0 ; i < m ; i++)
{
printf(FORMAT,DATA); //将录入的信息按指定格式输出
}
}
运行界面:
(10)退出程序
这一部分的代码其实就在main.c中,读者自己去体会吧,这里不做过多说明。
至此,学生管理系统程序实现和功能验证已完成。代码难度适中,读者可以自己去细心体会。博主还是在校大学生,实践能力不足,有错误的地方还请大家批评指正,共同进步!