C语言学生管理系统
源代码
#define _CRT_SECURE_NO_DEPRECATE
#include <stdio.h>
#include <malloc.h>
#include <string.h>
#include <stdlib.h>
#include <iostream>
using namespace std;
// 定义结构体并别名NODE
typedef struct node
{
struct node* next;
// 学号
int num;
// 姓名
char name[100];
// 年龄
int age;
}NODE;
// 声明函数
char menu1();
NODE* createn();
void traveln(NODE* head);
NODE* appendn(NODE* head, int num, char name[100], int age);
void saveStuInfo(NODE* head);
NODE* readStuInfo(NODE* head);
NODE* del2n(NODE* head, int num);
NODE* findn(NODE* head, int num);
NODE* insertn(NODE* head, int num,char name[100], int age);
NODE* updateStuInfo(NODE* head, int num,char name[100], int age);
int main()
{
char m = '0';
NODE* head = NULL;
head = readStuInfo(head);
// initn(head);
// 学号,年龄
int num,age;
// 姓名
char name[100];
while (m != '6')
{
m = menu1();
// 是否操作标志
char flag = 'n';
switch (m)
{
case '1':
printf("\n\n\t请输入学号:");
cin >> num;
printf("\n\n\t请输入姓名:");
cin >> name;
printf("\n\n\t请输入年龄:");
cin >> age;
head = appendn(head, num, name, age);
saveStuInfo(head);
cout << "\n\t添加成功" << endl;
cout << "\t是否返回菜单继续操作(y/n)";
flag = 'n';
cin >> flag;
if (flag != 'y') {
exit(0);
}
break;
case '2':
traveln(head);
cout << "\t是否返回菜单继续操作(y/n)";
flag = 'n';
cin >> flag;
if (flag != 'y') {
exit(0);
}
break;
case '3': printf("\n\n\t请输入学号:");
cin >> num;
del2n(head,num);
cout << "\n\t删除成功\n" << endl;
cout << "\t是否返回菜单继续操作(y/n)";
flag = 'n';
cin >> flag;
if (flag != 'y') {
exit(0);
}
break;
case '4':
printf("\n\n\t请输入要修改学号:");
cin >> num;
printf("\n\n\t请输入姓名:");
cin >> name;
printf("\n\n\t请输入年龄:");
cin >> age;
updateStuInfo(head,num,name,age);
cout << "\n\t修改成功\n" << endl;
cout << "\t是否返回菜单继续操作(y/n)";
flag = 'n';
cin >> flag;
if (flag != 'y') {
exit(0);
}
break;
case '5':
printf("\n\n\t请输入要查询学生的学号:");
cin >> num;
NODE* seachHead = findn(head,num);
cout << "\n\t学生基本信息\n" << endl;
cout << "\t------------------------------------------------------------------------------\n" <<endl;
cout << "\t\t学号\t\t\t\t姓名\t\t\t\t年龄\n";
// 判断链表尾
//cout << "head=" << head << endl;
cout << "\n\t\t" << seachHead->num;
cout <<"\t\t\t\t" << seachHead->name;
cout << "\t\t\t\t" << seachHead->age << "\n";
cout << "\n\t------------------------------------------------------------------------------\n" <<endl;
cout << "\t是否返回菜单继续操作(y/n)";
flag = 'n';
cin >> flag;
if (flag != 'y') {
exit(0);
}
break;
}
}
printf("\n\n\t退出成功");
}
// 自编的菜单函数
char menu1()
{
char c;
// 清屏
// system("cls");
// 清输入队列
fflush(stdin);
printf("\n\n\t 学生信息管理系统 \n");
printf("\n\n\t ============= 菜单列表 =============\n");
// 显示菜单选项1
printf("\n\n\t 1-学生基本信息录入与保存");
// 显示菜单选项2
printf("\n\n\t 2-学生基本信息的显示");
printf("\n\n\t 3-学生基本信息的删除");
printf("\n\n\t 4-学生基本信息的修改");
printf("\n\n\t 5-学生基本信息的查询");
// 显示菜单选项5-退出
printf("\n\n\t 6-退出系统\n");
do
{
// 输入,并排除非法按键
printf("\n\n\t 请输入菜单列表前的序号 : ");
cin >> c;
if (c < '0' || c>'6')
printf("\n\n\t 输入的数字不在菜单列表内,请重新输入\n");
} while (c < '0' || c>'6');
return c;
}
// 保存文件
void saveStuInfo(NODE* head)//保存学生信息到文件
{
FILE* fp;
NODE* p = head;
if ((fp = fopen("student.txt", "w")) == NULL)// 以可写的方式打开当前目录下的.txt
{
printf("不能打开此文件,请按任意键退出\n");
exit(1); //异常退出
}
while (p)
{
fprintf(fp, "%d %s %d \n", p->num, p->name, p->age);
p = p->next;
}
fclose(fp);
}
NODE* readStuInfo(NODE* head) //运行前把文件内容读取到电脑内存
{
FILE* fp;
fp = fopen("student.txt", "rb+");
if (fp == NULL)
{
printf("文件不存在,添加数据后将自动创建\n");
return head;
// exit(0); //终止程序
}
int nu;//学号
char nam[100];//名字
int ag;//年龄
fscanf(fp, "%d %s %d", &nu,nam,&ag);
NODE* n = (NODE*)malloc(sizeof(NODE));
NODE* p;
n->num = nu;
strcpy(n->name, nam);//把后者的内容拷贝到前者中
n->age = ag;
n->next = NULL;
head = n;
p = head;
while (!feof(fp))
{
fscanf(fp, "%d %s %d", &nu,nam,&ag);
if (feof(fp)) break;
NODE* n = (NODE*)malloc(sizeof(NODE));
n->num = nu;
strcpy(n->name, nam);//把后者的内容拷贝到前者中
n->age = ag;
n->next = NULL;
p->next = n;
p=n;
}
cout << "\t读取文件数据成功,数据如下:\n" << endl;
traveln(head);
fclose(fp);
return head;
}
// 产生一个新链表,仅1节点
NODE* createn()
{
NODE* head = NULL;
// 新申请一个节点空间
head = (NODE*)malloc(sizeof(NODE));
if (head == NULL)
{
printf("申请空间出错。");
exit(1);
}
// 新建的唯一节点也是头、也是尾
head->next = NULL;
// 可以在此加语句输入数据
return head;
}
//遍历整个链表
void traveln(NODE *head)
{
if (head == NULL)
printf("\t空数据 \n\n");
else
cout << "\n\t学生基本信息\n" << endl;
cout << "\t------------------------------------------------------------------------------\n" <<endl;
cout << "\t\t学号\t\t\t\t姓名\t\t\t\t年龄\n";
// 判断链表尾
while (head != NULL)
{
//cout << "head=" << head << endl;
cout << "\n\t\t" <<head->num;
cout <<"\t\t\t\t" <<head->name;
cout << "\t\t\t\t" <<head->age << "\n";
// 移动指针
head = head->next;
}
cout << "\n\t------------------------------------------------------------------------------\n" <<endl;
}
//在链表尾部添加节点
NODE* appendn(NODE *head, int num, char name[100], int age)
{
NODE *p, *q;
if (head == NULL)
{
head = createn();
head->num = num;
strcpy(head->name, name);
head->age = age;
}
else
{
p = head;
// 移动到链表尾,准备后面添加
while (p->next != NULL)
p = p->next;
// 新申请一个节点空间
q = (NODE*)malloc(sizeof(NODE));
if (q == NULL)
{
printf("申请空间出错。");
exit(1);
}
// 新建节点是尾
q->next = NULL;
// 添加到原链表尾
p->next = q;
q->num = num;
strcpy(q->name, name);
q->age = age;
}
// 有返回值是因为为了处理空链表,否则可以不要
return head;
}
NODE* insertStu(NODE *head)
{
NODE *p, *q;
if (head == NULL)
{
return NULL;
}
else
{
p = head;
// 移动到链表尾,准备后面添加
while (p->next != NULL)
p = p->next;
// 新申请一个节点空间
q = (NODE*)malloc(sizeof(NODE));
if (q == NULL)
{
printf("申请空间出错。");
exit(1);
}
}
// 有返回值是因为为了处理空链表,否则可以不要
return head;
}
NODE* del2n(NODE* head, int num) // 在链表中删除多个节点
{
NODE* p = head, * q;
if (p != NULL)
{
while (head != NULL && head->num == num) // 如果头节点就是要删除对象
{
head = p->next;
free(p);
p = head;
}
while (p != NULL)
{
q = p;
p = p->next;
if (p != NULL && p->num == num) // 删除一个中间节点
{
q->next = p->next;
free(p);
p = q;
}
}
}
saveStuInfo(head);
return head; // 返回值是链表头
}
NODE* insertn(NODE* head, int num,char name[100], int age) // 在链表某节点后插入1个节点
{
NODE* p, * q;
if (head == NULL)
{
head = createn();
head->num = num;
strcpy(head->name, name);
head->age = age;
}
else
{
p = head;
while (p->next != NULL && p->num != num) // 移动到位置,准备后面添加
p = p->next;
q = (NODE*)malloc(sizeof(NODE)); // 新申请一个节点空间
if (q == NULL)
{
printf("申请空间出错。");
exit(1);
}
q->next = p->next; // 插入新建节点
p->next = q; // 添加到位置后
q->num = num;
q->age = age; // 将实参数据加入
strcpy(q->name, name);
}
return head; // 有返回值是因为为了处理空链表,否则可以不要
}
NODE* updateStuInfo(NODE* head, int num,char name[100], int age) // 在链表某节点后插入1个节点
{
NODE* p;
if (head == NULL)
{
head = createn();
head->num = num;
strcpy(head->name, name);
head->age = age;
}
else
{
p = head;
while (p->next != NULL && p->num != num) // 移动到位置,准备后面添加
p = p->next; // 添加到位置后
p->age = age; // 将实参数据加入
strcpy(p->name, name);
}
saveStuInfo(head);
return head; // 有返回值是因为为了处理空链表,否则可以不要
}
NODE* findn(NODE* head, int num) // 在链表中查找1个节点
{
while (head != NULL && head->num != num)
head = head->next;
return head; // 返回值是找到的节点的指针
}
需求分析
设计的学生信息管理系统是用户管理学生的信息,通过文件存储学生信息数据,通过交互实现对学生基本信息的录入和存取,并且可以浏览学生的相关信息,然后可以删除和插入学生的相关信息,同时可以按学号查询此学生的相关信息。
概要设计
菜单界面与各模块间的结构关系图。学生信息管理系统由六个模块组成,系统的模块结构如图1所示。
详细设计
学生基本信息录入和保存
在菜单输入 1,进入学生信息录入,依次输入学号,姓名,年龄,回车就能保存。具体流程为创建一个链表,判断头节点是否为空,为空就重新创建,申请新的节点空间,将 next 设置为 NULL,有了链表,一直循环到链表最后,也就是 next 为 NULL,接着申请一个节点存放学生信息,然后连接起来。
学生基本信息的显示
先读取文件数据,如果文件有数据会存入 head 中,之后判读链表是否有数据,没有则打印空数据,有数据就遍历链表,循环打印每个节点的数据,并向后移动指针,直到全部打印完毕。
学生基本信息的删除
读取文件数据,输入学号,遍历链表,移动指针,找到节点学号和输入的学号相同的节点,删除节点,上一个节点指向下个节点,最后保存到文件中。
学生基本信息的修改
读取文件数据,输入学号,姓名,年龄,传入链表,判断链表是否存在,不存在则创建新链表,存在就找到节点学号数据与输入学号相同的节点,修改节点中的数据,保存到文件中。
学生基本信息的查询
传入链表,输入学生学号,判断链表是否存在,存在就找到节点学号数据与输入学号相同的节点,打印出学生信息。
退出系统
菜单编号是 6 ,如果退出,则打印退出成功。
流程图
录入学生基本数据流程
学生基本信息的显示
学生基本信息删除
学生基本信息修改
学生基本信息查询
退出系统
运行截图
菜单页面可以选择不同的学生基本信息操作,下图分别是数据读取,菜单界面,学生的添加,文件保存以及学生数据的展示。
读取文件加载学生信息
查询单个学生数据
添加学生信息
显示学生信息(包括文件中的信息)
删除学生基本信息
修改学生基本信息