程序员的必经之路吧,学生管理系统。在制作过程中体会到了编写一个具体可用的软件而要做的工作,无论是编写前的准备,还是编写过程中每个细节的处理,都让我理解了这份工作是个什么样子。程序并不是抬手就来,一个软件要完整,同时还要将每个功能部分区分开,所以在编写之前一定要先规划清楚,这是一项工程。逻辑要严密,编程完全就是对逻辑思维的考验,大大小小的函数、语句都是靠逻辑连接起来的。基础知识要扎实,在我现在这个阶段,经常会遇到为干掉bug而苦思半天,在逻辑上寻觅没有出口,其实只是对用法不了解,上课时认为那种不太常考的东西不用太费心,只要把主要的知识记住就行,但事实上每个知识点都是有用的,接下来使用数组,动态数组,单向链表,文件操作等来实现C语言:学生管理系统。
这里使用的是VS2019,如果你使用的是CodeBlocks或DEV C++等请先把第一行注释掉。
对学生信息管理系统,要求完成以下基本任务:
1.改写程序为良好程序风格(文档注释,函数注释,语句注释)。
2.将功能补充完全(基于文件处理,完成刷新和保存功能)。
3.将学生信息改为更好的数据组织,而非离散形式(结构体)。
4.可将程序中的不足(如数据验证)等根据自己的能力与理解完成。
5.用使用C语言做一个学生信息管理系统,我的想法是先把需要的一些变量封装在结构体中,然后结合以前学过的数据结构知识(链表),做一些增删查改的操作,并将其保存在文件中。
群内有各种学习资料,欢迎大家一起来学习哦~
如果大家遇到什么问题也欢迎大家进群讨论哦~
qq群:759252814
#define _CRT_SECURE_NO_WARNINGS
#include
#include
#include
#include
#include
/**********************保存学生信息的结构体**********************/
typedef struct Student //使用typedef为struct Student起别名为XIN
{
char Student_id[30]; //学生编号
char name[30]; //学生姓名
int age; //学生年龄
char sex[5]; //学生性别
float Ascore; //语文分数
float Bscore; //数学分数
float Cscore; //英语分数
float Count; //三科总分
struct Student* next; //指向下一个地址
}XIN;
int color(int n); //字体颜色
void gotoxy(int x, int y); //字体位置
void Aframe(); //边框 1号 蓝 紫
void Bframe(); //边框 2号 蓝 红
void Main_interface(); //主界面
void Write_in(); //输入信息
void Output(); //输出信息
void Lookup(); //查找信息
void Sort(); //成绩排序
void Delete(); //删除信息
/**********************主界面**********************/
void Main_interface()
{
system("cls"); //每次调用 Main_interface() 函数时调用一次 system("cls") 进行清屏函数
gotoxy(19, 2); //字符打印位置,如最左上角的坐标为 0.0
color(13); //接下来打印的字体颜色如:10为绿色,13为紫色
printf("===========学 生 管 理 系 统 菜 单===========\n");
Aframe(); //使用边框 1号
color(2);
gotoxy(60, 1);
printf("欢迎您的使用! ^_^");
color(14);
gotoxy(24, 6);
color(9);
printf("=======请选择功能列表=======\n");
color(10);
gotoxy(12, 8);
printf("1.添加学生信息\n");
gotoxy(12, 10);
color(14);
printf("2.查看学生信息n");
gotoxy(12, 12);
color(13);
printf("3.查找学生信息\n");
gotoxy(12, 14);
color(11);
printf("4.按成绩排序\n");
gotoxy(12, 16);
color(9);
printf("5.删除学生信息\n");
color(7);
gotoxy(12, 18);
printf("6.退出程序");
label: //标签 用于goto语句
gotoxy(26, 22);
color(14);
printf("本程序会自动读取 请选择[ ]\b\b");
char ch; //存放输入的字符
ch = _getch(); //读取键盘输入的一个字符不显示 \不回显函数
putchar(ch);
switch (ch)
{
case '1':system("cls"); Write_in(); break; //system("cls"); 清屏函数
case '2':system("cls"); Output(); break;
case '3':system("cls"); Lookup(); break;
case '4':system("cls"); Sort(); break;
case '5':Delete(); break;
case '6':system("cls"); exit(0); break; //exit(0):结束程序返回值为0
case 27 :system("cls"); exit(0); break; //27为Esc的ASCLL编号
default:goto label; break; //goto label:无条件跳转至标签 label 处
};
}
int main(void)
{
Main_interface();
return 0;
}
/**********************输入信息**********************/
void Write_in()
{
FILE* fp; //文件指针
XIN temp; //为当前输入内容
//打开文件并判断是否打开成功或创建成功,ab+是以二进制追加的方式打开,如果找不到该文件则创建一个studentA.datd文件来储存信息,如果也创建失败则报错并结束程序
if ((fp = fopen("studentA.datd", "ab+")) == NULL)
{
printf("创建文件或添加信息失败! 错误代码:0x001");
exit(1);
}
int count = 0; //当前输入的学生人数
while (TRUE) //一直输入信息直到break跳出
{
system("cls");
count++;
gotoxy(17, 2);
color(13);
printf("===========添 加 学 生 信 息 界 面===========\n");
Aframe();
gotoxy(10, 6);
color(10);
printf("请输入第%d位学生的学号:", count);
scanf("%s", temp.Student_id);
if (strcmp(temp.Student_id, "-1") == 0) //当学号输入为-1时退出输入,把信息储存到文件并关闭文件
{
break;
}
gotoxy(10, 8);
printf("请输入第%d位学生的名字:", count);
scanf("%s", temp.name);
gotoxy(10, 10);
printf("请输入第%d位学生的性别:", count);
scanf("%s", temp.sex);
gotoxy(10, 12);
printf("请输入第%d位学生的年龄:", count);
scanf("%d", &temp.age);
gotoxy(10, 14);
printf("请输入第%d位学生的语文成绩:", count);
scanf("%f", &temp.Ascore);
gotoxy(10, 16);
printf("请输入第%d位学生的数学成绩:", count);
scanf("%f", &temp.Bscore);
gotoxy(10, 18);
printf("请输入第%d位学生的英语成绩:", count);
scanf("%f", &temp.Cscore);
temp.Count = temp.Ascore + temp.Bscore + temp.Cscore;
fwrite(&temp, sizeof(XIN), 1, fp);
gotoxy(26, 22);
color(14);
printf("是否要继续'y'或者'n'[ ]\b\b");
char ch;
label: //判断
ch = _getch();
if (ch == 'y' || ch == 'Y')
{
printf("\n");
}
else if (ch == 'n' || ch == 'N')
{
fclose(fp);
Main_interface();
}
else
goto label;
}
fclose(fp);
}
/**********************输出信息**********************/
void Output()
{
system("cls");
XIN temp;
FILE* fp;
char ch;
//打开文件并判断是否打开成功,rb是以二进制只读的方式打开,如果找不到则报错并结束程序
if ((fp = fopen("studentA.datd", "rb")) == NULL)
{
printf("打开文件失败,请确定是否创建了该文件! 错误代码:0x002");
exit(1);
}
int i = 1;
int count = 0; //判断是否存文件中读取信息
fread(&temp, sizeof(XIN), 1, fp);
while (!feof(fp)) //feof用检测流上的文件结束符,其返回值有两种情况:如果遇到文件结束,函数值为非零值,否则函数值为0
{
system("cls");
count = 1;
Aframe();
gotoxy(19, 2);
color(13);
printf("=========== 查 看 信 息 界 面===========\n");
gotoxy(18, 9);
color(13);
printf("学号为:%s\n", temp.Student_id);
gotoxy(48, 9);
color(10);
printf("名字为:%s\n", temp.name);
gotoxy(18, 12);
color(9);
printf("性别为:%s\n", temp.sex);
gotoxy(48, 12);
color(13);
printf("年龄为:%d\n", temp.age);
gotoxy(18, 15);
color(13);
printf("语文为:%.1f\n", temp.Ascore);
gotoxy(48, 15);
color(10);
printf("数学为:%.1f\n", temp.Bscore);
gotoxy(18, 18);
color(10);
printf("英语为:%.1f\n", temp.Cscore);
gotoxy(48, 18);
color(9);
printf("总分为:%.1f\n", temp.Count);
gotoxy(30, 6);
color(14);
printf("第%d位学生的信息", i);
gotoxy(26, 22);
color(14);
printf("本程序会自动读取 请选择[ ]\b\b");
label:
ch = _getch();
if (ch == 80) //下键的ASCII编码
i++;
else if (ch == 27)
Main_interface(); //Esc的ASCII编码
else if (ch == 72) //上键的ASCII编码
{
fseek(fp, -192L, SEEK_CUR); //文件指针在当前位置向后移动192个字节,结构体 struct Student 所占的字节为:96
i--;
}
else
goto label;
fread(&temp, sizeof(XIN), 1, fp);
}
fclose(fp);
if (count == 0) //如果为0则说明未从文件中读取出内容文件为空
{
Bframe();
gotoxy(19, 2);
color(13);
printf("=========== 查 看 信 息 界 面===========\n");
color(12);
gotoxy(25, 8);
printf("没 有 添 加 任 何 信 息 !");
gotoxy(23, 15);
color(13);
printf("按Esc键返回主页面回车键添加 [ ]\b\b");
char ch;
label2:
ch = _getch();
if (ch == 27)
Main_interface();
else if (ch == 13) //空格键的ASCII编码
Write_in();
else
goto label2;
}
else
{
gotoxy(24, 22);
color(10);
printf("请按Esc返回本程序会自动读取 [ ]\b\b"); //结束返回
label3:
ch = _getch();
if (ch == 27)
Main_interface();
else
goto label3;
}
}
/**********************查找信息**********************/
void Lookup()
{
FILE* fp;
XIN temp;
char Name[30];
gotoxy(15, 2);
color(11);
printf("=========== 查 找 学 生 信 息 界 面===========\n");
Bframe();
color(14);
gotoxy(20, 8);
printf("请输入需要找查的学生名字:");
scanf("%s", Name);
gotoxy(27, 15);
color(13);
printf("按Esc键返回主页面[ ]\b\b");
if ((fp = fopen("studentA.datd", "rb")) == NULL)
{
printf("打开文件失败,请确定是否创建了该文件! 错误代码:0x003");
exit(1);
}
int Count = 0;
fread(&temp, sizeof(XIN), 1, fp);
while (!feof(fp))
{
system("cls");
if (strcmp(temp.name, Name) == 0) //从文件中读取如果匹配则输出
{
Count = 1;
Aframe();
gotoxy(15, 2);
color(13);
printf("=========== 查 找 学 生 信 息 界 面===========\n");
gotoxy(18, 9);
color(13);
printf("学号为:%s\n", temp.Student_id);
gotoxy(48, 9);
color(10);
printf("名字为:%s\n", temp.name);
gotoxy(18, 12);
color(9);
printf("性别为:%s\n", temp.sex);
gotoxy(48, 12);
color(13);
printf("年龄为:%d\n", temp.age);
gotoxy(18, 15);
color(13);
printf("语文为:%.1f\n", temp.Ascore);
gotoxy(48, 15);
color(10);
printf("数学为:%.1f\n", temp.Bscore);
gotoxy(18, 18);
color(10);
printf("英语为:%.1f\n", temp.Cscore);
gotoxy(48, 18);
color(9);
printf("总分为:%.1f\n", temp.Count);
gotoxy(30, 6);
color(14);
printf("教师“%s”的信息如下", Name);
gotoxy(30, 22);
color(14);
printf("按Esc键退出 [ ]\b\b");
char ch;
label:
ch = _getch();
if (ch == 27)
{
Main_interface();
}
else
{
goto label;
}
break;
}
fread(&temp, sizeof(XIN), 1, fp);
}
if (Count == 0)
{
system("cls");
gotoxy(15, 2);
color(11);
printf("=========== 查 找 学 生 信 息 界 面===========\n");
Bframe();
color(12);
gotoxy(25, 8);
//printf(" ");
gotoxy(25, 8);
printf("没有找到该学生的任何信息!");
gotoxy(27, 13);
color(13);
printf("按Esc键返回主页面[ ]\b\b");
char ch2;
label2:
ch2 = _getch();
if (ch2 == 27)
Main_interface();
else
goto label2;
}
}
/**********************成绩排序**********************/
void Sort()
{
FILE* fp;
XIN temp;
int Acount = 0;
int Bcount = 0;
int NUMBER = 0; //通过循环统计有多少位学生,并以NUMBER的值创建一个动态数组
if ((fp = fopen("studentA.datd", "rb")) == NULL)
{
printf("打开文件失败,请确定是否创建了该文件! 错误代码:0x004");
exit(1);
}
fread(&temp, sizeof(XIN), 1, fp);
while (!feof(fp)) //feof用检测流上的文件结束符,其返回值有两种情况:如果遇到文件结束,函数值为非零值,否则函数值为0
{
Acount = 1;
NUMBER++;
fread(&temp, sizeof(XIN), 1, fp);
}
fclose(fp);
if (Acount == 0) //用于判断文件中是否有信息,如果没有则提示
{
Bframe(); //边框二号
gotoxy(19, 2);
color(13);
printf("=========== 按 成 绩 排 序 界 面 ===========\n");
color(12);
gotoxy(25, 8);
printf("没 有 添 加 任 何 信 息 !");
gotoxy(23, 14);
color(13);
printf("按Esc键返回主页面回车键添加 [ ]\b\b");
char ch;
label2:
ch = _getch();
if (ch == 27)
Main_interface();
else if (ch == 13) //空格键的ASCII编码
Write_in();
else
goto label2;
}
if ((fp = fopen("studentA.datd", "rb")) == NULL)
{
printf("打开文件失败,请确定是否创建了该文件! 错误代码:0x005");
exit(1);
}
XIN* information;
information = (XIN*)malloc(sizeof(XIN) * NUMBER);
int i = 0; //用于动态数组的下标
fread(&temp, sizeof(XIN), 1, fp);
while (!feof(fp)) //feof用检测流上的文件结束符,其返回值有两种情况:如果遇到文件结束,函数值为非零值,否则函数值为0
{
strcpy(information[i].Student_id, temp.Student_id); ////把读取出来的内容赋值给结构体数组information
strcpy(information[i].name, temp.name);
strcpy(information[i].sex, temp.sex);
information[i].age = temp.age;
information[i].Ascore = temp.Ascore;
information[i].Bscore = temp.Bscore;
information[i].Cscore = temp.Cscore;
information[i].Count = temp.Count;
fread(&temp, sizeof(XIN), 1, fp);
i++;
}
fclose(fp);
XIN Temp;
for (int i = 0; i < NUMBER; i++)
{
for (int j = i + 1; j < NUMBER; j++)
{
if (information[i].Count < information[j].Count)
{
Temp = information[i];
information[i] = information[j];
information[j] = Temp;
}
}
}
for (int i = 0; i < NUMBER; i++)
{
system("cls");
Aframe();
gotoxy(19, 2);
color(13);
printf("=========== 查 看 信 息 界 面===========\n");
gotoxy(18, 9);
color(13);
printf("学号为:%s\n", information[i].Student_id);
gotoxy(48, 9);
color(10);
printf("名字为:%s\n", information[i].name);
gotoxy(18, 12);
color(9);
printf("性别为:%s\n", information[i].sex);
gotoxy(48, 12);
color(13);
printf("年龄为:%d\n", information[i].age);
gotoxy(18, 15);
color(13);
printf("语文为:%.1f\n", information[i].Ascore);
gotoxy(48, 15);
color(10);
printf("数学为:%.1f\n", information[i].Bscore);
gotoxy(18, 18);
color(10);
printf("英语为:%.1f\n", information[i].Cscore);
gotoxy(48, 18);
color(9);
printf("总分为:%.1f\n", information[i].Count);
gotoxy(30, 6);
color(14);
printf("第%d位学生的信息", i + 1);
gotoxy(26, 22);
color(14);
printf("本程序会自动读取 请选择[ ]\b\b");
char ch;
label:
ch = _getch();
if (ch == 80) //下键的ASCII编码,当按下键时什么也不做等待for循环继续
{
}
else if (ch == 27)
Main_interface(); //Esc的ASCII编码
else if (ch == 72) //上键的ASCII编码
{
i -= 2;
}
else
goto label;
}
char ch;
gotoxy(24, 22);
color(10);
printf("请按Esc返回本程序会自动读取 [ ]\b\b"); //结束返回
label3:
ch = _getch();
if (ch == 27)
Main_interface();
else
goto label3;
}
/**********************删除信息**********************/
void Delete()
{
system("cls");
FILE* fp;
XIN temp;
XIN* h, * p, * q; //*h代表链表的头指针,*p代表链表上一个的指针.*q代表当前指针
int Const = 0;
char Name[30];
gotoxy(15, 2);
color(11);
printf("=========== 删 除 学 生 信 息 界 面===========\n");
Bframe();
color(14);
gotoxy(20, 8);
printf("请输入需要删除的学生名字:");
scanf("%s", Name);
if ((fp = fopen("studentA.datd", "rb")) == NULL)
{
printf("打开文件失败,请确定是否创建了该文件! 错误代码:0x006");
exit(1);
}
h = p = (XIN*)malloc(sizeof(XIN));
fread(&temp, sizeof(XIN), 1, fp);
while (!feof(fp)) //feof用检测流上的文件结束符,其返回值有两种情况:如果遇到文件结束,函数值为非零值,否则函数值为0
{
if (strcmp(temp.name, Name) == 0)
{
Const = 1;
fread(&temp, sizeof(XIN), 1, fp);
continue;
}
else
{
q = (XIN*)malloc(sizeof(XIN)); //把读取出来的内容赋值给q指向的结构体
strcpy(q->Student_id, temp.Student_id);
strcpy(q->name, temp.name);
strcpy(q->sex, temp.sex);
q->age = temp.age;
q->Ascore = temp.Ascore;
q->Bscore = temp.Bscore;
q->Cscore = temp.Cscore;
q->Count = temp.Count;
p->next = q;
p = q;
fread(&temp, sizeof(XIN), 1, fp);
}
}
p->next = NULL;
if ((fp = fopen("studentA.datd", "rb")) == NULL)
{
printf("打开文件失败,请确定是否创建了该文件! 错误代码:0x006");
exit(1);
}
p = h->next; //使p指向链表的第一个节点
while (p->next != NULL)
{
fwrite(p, sizeof(XIN), 1, fp);
p = p->next;
}
fclose(fp);
if (Const == 1)
{
system("cls");
gotoxy(15, 2);
color(13);
printf("=========== 删 除 学 生 信 息 界 面===========\n");
Bframe();
color(10);
gotoxy(31, 8);
printf("删 除 成 功 !");
gotoxy(27, 14);
color(13);
printf("按Esc键返回主页面[ ]\b\b");
char ch;
labelA:
ch = _getch();
if (ch == 27)
Main_interface();
else
goto labelA;
}
else
{
system("cls");
gotoxy(15, 2);
color(13);
printf("=========== 删 除 学 生 信 息 界 面===========\n");
Bframe();
color(12);
gotoxy(25, 8);
printf("没有找到该学生的信息!");
gotoxy(27, 14);
color(13);
printf("按Esc键返回主页面[ ]\b\b");
char ch;
labelB:
ch = _getch();
if (ch == 27)
Main_interface();
else
goto labelB;
}
}
void Aframe() //彩色框架 1号 蓝 紫 中偏大
{
int i, j;
static int b, n;
for (i = 8; i <= 69; i++)
{
b = 2, n = 2;
for (j = 4; j <= 20; j++)
{
b++;
n++;
if (i == 8 || i == 69)
{
if (b % 2 == 0)
{
color(13);
}
else if (b % 1 == 0)
{
color(9);
}
gotoxy(i, j);
printf("|");
}
if (j == 4 || j == 20)
{
if (b % 2 == 0)
{
color(13);
}
else if (b % 1 == 0)
{
color(9);
}
gotoxy(i, j);
printf("=");
}
}
}
}
void Bframe() //彩色边框 2 蓝 红 偏小
{
int i, j;
static int b, n;
for (i = 8; i <= 69; i++)
{
b = 2, n = 2;
for (j = 4; j <= 12; j++)
{
b++;
n++;
if (i == 8 || i == 69)
{
if (b % 2 == 0)
{
color(12);
}
else if (b % 1 == 0)
{
color(9);
}
gotoxy(i, j);
printf("|");
}
if (j == 4 || j == 12)
{
if (b % 2 == 0)
{
color(12);
}
else if (b % 1 == 0)
{
color(9);
}
gotoxy(i, j);
printf("=");
}
}
}
}
int color(int n) //颜色 -----------------------
{
SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), n);
return 0;
}
void gotoxy(int x, int y) //位置 --------------------------
{
COORD pos;
pos.X = x;
pos.Y = y;
SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), pos);
}
}