介绍
这是一个比较简单的纯c实现的学生管理系统,主要实现就是链表+结构体。基本功能有增加,插入,查询。因为删除比较方便的原因这里选用了双向链表,当然单身链表也是可以的,但是删除的话就稍微麻烦些。好了,闲话就这么多了,下面来讲解下代码的实现。
实现
首先定义学生的信息、链表的信息以及课程的一些相差信息,如下:
#define MAX_NAME_LENGTH20
#define MAX_COURSE_NAME_LENGTH30
#define MAX_COURSE5
static char g_course[MAX_COURSE][MAX_COURSE_NAME_LENGTH] =
{"c语言", "算法", "c++语言", "英语", "数学"};
///@brief 定义学生信息
typedef struct _Student
{
int no;///< 学号 唯一
char name[MAX_NAME_LENGTH];///< 姓名
float score[MAX_COURSE];///< 每个课程的分数
}Student;
///@brief 定义链表结点
typedef struct _Node
{
Student stu;///< 学生信息
struct _Node* prev;///< 前一个结点
struct _Node* next;///< 下一个结点
}Node;
///@brief 定义链表
typedef struct _List
{
Node* head;///< 头结点
int length;///< 链表长度
}List;
这里用到宏来代替课程的数量和姓名的长度,方便直接修改宏而不用到程序各处去查找。这里也用到了一个数组来定义课程的名称,方便到时候增加或者减少课程。
既然基本信息有了,接着就是初始化了:
static List* g_list = 0;///< 定义一个全局链表
///@brief 初始化链表
void init()
{
g_list = (List*)malloc(sizeof(List));
g_list->head = (Node*)malloc(sizeof(Node));
g_list->head->next = g_list->head->prev = g_list->head;
g_list->length = 0;
}
这里初始化用上了哨兵,方便后面的链表删除,插入操作。
以下是链表的操作,这里就不详细说明了,有需要的可以去另一个文章查找:双向链表哨兵版。
///@brie 根据学号查找结点
///@param no 学生
///@return Node* 返回学生的结点指针
Node* search(int no)
{
Node* p = g_list->head->next;
while(g_list->head != p && p->stu.no != no)
{
p = p->next;
}
return p;
}
///@brief 插入学生结点到链表中
///@param node 学生结点
void insert(Node* node)
{
node->next = g_list->head->next;
g_list->head->next->prev = node;
g_list->head->next = node;
node->prev = g_list->head;
++ g_list->length;
}
///@brief 根据结点删除学生
///@param node 学生结点
void erase(Node* node)
{
node->prev->next = node->next;
node->next->prev = node->prev;
-- g_list->length;
}
///@brief 创建一个结点
Node* createNode()
{
Node* node = (Node*)malloc(sizeof(Node));
node->prev = g_list->head;
node->next = g_list->head;
return node;
}
下面讲讲这里实现的一些菜单:
第一个就是增加学生:
///@brief 增加学生
void addStudentMenu()
{
int i = 0;
Node* pFind;
Node* node = createNode();
/// 判断学号存在标志
int isExistFlag = 0;
do
{
isExistFlag = 0;
printf("请输入学生的信息:\n");
printf("学号:");
scanf("%d", &(node->stu.no));
if (0 == node->stu.no)
{
return;
}
pFind = search(node->stu.no);
if (pFind != g_list->head)
{
isExistFlag = 1;
printf("此学号已经存在,请重新输入。返回请输入0。\n");
}
}while(1 == isExistFlag);
printf("姓名:");
scanf("%s", node->stu.name);
for (i = 0; i < MAX_COURSE; ++ i)
{
printf("%s分数:", g_course[i]);
scanf("%f", &(node->stu.score[i]));
}
insert(node);
printf("插入学生信息成功。\n");
}
这里,需要输入学生学号来判断是否已经存在,如果存在则就要重新输入,输入完成以后,再输入学生其实信息,最后保存到链表中去。
删除学生:
///@brief 删除学生
void deleteStudentMenu()
{
int no = 0;
Node* pFind;
int isExistFlag = 0;
do
{
isExistFlag = 0;
printf("请输入需要删除的学生的信息:\n");
printf("学号:");
scanf("%d", &no);
if (0 == no)
{
return;
}
pFind = search(no);
if (pFind == g_list->head)
{
isExistFlag = 1;
printf("此学号不存在,请重新输入。返回请输入0。\n");
}
}while(1 == isExistFlag);
erase(pFind);
printf("删除学生成功。\n");
}
删除学生之前也判断一下,此学号是否存在,不存在则重新输入,存在的话,就可以删除此学生。
然后可以通过查找所有学生来判断学生是否删除成功:
///@brief 查看所有学生
void selectAllStudentMenu()
{
Node* p;
int i = 0;
if (0 == g_list->length)
{
printf("没有学生信息,请增加学生信息以后再查看。\n");
return;
}
printf("学号 姓名 ");
for (i = 0; i < MAX_COURSE; ++ i)
{
printf("%s ", g_course[i]);
}
printf("\n");
p = g_list->head->next;
while(g_list->head != p)
{
printf("%d %6s ", p->stu.no, p->stu.name);
for (i = 0; i < MAX_COURSE; ++ i)
{
printf("%4.2f ", p->stu.score[i]);
}
printf("\n");
p = p->next;
}
}
这里会根据插入的顺序来显示学生的信息。当然,在这里也可以实现一下排序,根据学号,或者是某科目的成绩来排名,这都是可以的。
下面就是主菜单和退出功能了,这个比较简单:
///@brie 退出
void exitMenu()
{
printf("谢谢你的使用。\n");
}
///@brief 主菜单
void mainMenu()
{
int flag = -1;
while(0 != flag)
{
printf("1.增加学生\n");
printf("2.查看所有学生\n");
printf("3.删除学生\n");
printf("0.退出\n");
printf("请输入你需要的操作数(0-9):");
scanf("%d", &flag);
switch (flag)
{
case 0:
exitMenu();
break;
case 1:
addStudentMenu();
break;
case 2:
selectAllStudentMenu();
break;
case 3:
deleteStudentMenu();
break;
default:
printf("格式不对,请输入上面目录前面的数字。\n");
break;
}
}
}
当用户输入0时,则退出。
大概界面如下:
总结
总体来说,这是一个很精简的学生管理系统,还有很多功能没有,只能算是一个demo。主要是用来给多数初学者展示一下思路,怎么来编程,以及怎样来实现一些功能。这也是上面这份代码很多功能没有实现的原因,因为我想让大家自己去实现。然后展示出来。当然,如果大家在当中遇到什么问题可以留言给我,我会尽量帮大家解决。学生管理系统的文件操作版本:c语言学生管理系统之文件操作。
[download id=”1010″ template=”button”]