该代码可以完整运行,已包含全部代码!
1.序言:
这是博主第一次写博客记录自己的日常,分享给C语言的初学者但需要一个小项目练手。
项目名称:基于C语言的简易学生管理系统设计
功能:简易系统登录、显示操作菜单栏;学生信息录入、查找、修改、删除、展示;学生信息文件储存、加载;学生信息的统计、排序。
此为系统功能框架:
2.头文件和数据结构:
数据结构很简单,使用的是结构体。学生信息结构体包含学号id,姓名name,性别gender,分数score;学生列表结构体则包含学生结构体,当前人数count,容量capacity。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
// 定义学生结构体
typedef struct
{
int id; // 学号
char name[50]; // 姓名
char gender[10]; // 性别
float score; // 成绩
} Student;
//
// 定义学生列表结构体
typedef struct
{
Student *students; // 指向学生数组的指针
int count; // 当前学生数量
int capacity; // 当前容量
} StudentList;
3.学生信息录入功能实现
包含初始化学生列表、判断学号是否唯一(防止重复插入)、信息插入功能(该函数首先判断学生列表内容是否足够,不够则动态增加列表长度,然后依次输入信息、最后验证分数输入是否符合标准)。
// 初始化学生列表
void InitStudentList(StudentList *P, int capacity)
{
P->students = (Student *)malloc(capacity * sizeof(Student));
if (!P->students)
{
printf("学生列表初始化失败!");
exit(EXIT_FAILURE);
}
else
{
P->count = 0;
P->capacity = capacity;
}
}
//
// 判定学号是否唯一
int IsidUnique(StudentList *P, int id)
{
for (int i = 0; i < P->count; i++)
{
if (id == P->students[i].id) // 重复了
{
printf("该学生已存在系统内");
return 0;
}
}
return 1;
}
//
// 添加学生信息,带验证判断
void AddStudentList(StudentList *P)
{
if (P->count >= P->capacity) // 表明默认的结构体长度不够,需要实时扩展内存
{
int Newcapacity = P->capacity * 2; // 翻倍扩容
Student *NewStu = (Student *)realloc(P->students, sizeof(P->students) * Newcapacity);
if (!NewStu) // 若内存扩展失败,则退出
{
printf("内存扩展失败!\n");
exit(EXIT_FAILURE);
}
// 扩展成功,更新数据
P->capacity = Newcapacity;
P->students = NewStu;
}
Student *newstu = &P->students[P->count];
printf("请输入学号: ");
scanf("%d", &(newstu->id));
while (!IsidUnique(P, newstu->id))
{
printf("学号已存在,请重新输入学号: ");
scanf("%d", &(newstu->id));
}
printf("请输入姓名: ");
scanf("%s", newstu->name);
printf("请输入性别: ");
scanf("%s", newstu->gender);
printf("请输入成绩 (0-100): ");
scanf("%f", &(newstu->score));
// 验证成绩范围
while (newstu->score < 0 || newstu->score > 100)
{
printf("成绩应在0到100之间, 请重新输入成绩: ");
scanf("%f", &(newstu->score));
}
P->count++;
printf("信息输入成功!");
}
4.显示当前所有学生的信息
原理很简单,输入当前列表,遍历即可。
// 显示学生的信息
void displayStudent(StudentList *P)
{
if (P->count == 0)
{
printf("系统内无信息\n");
return;
}
printf("\n当前学生信息:\n");
printf("------------------------------------------------------------\n");
printf("| 学号 | 姓名 | 性别 | 成绩 |\n");
printf("------------------------------------------------------------\n");
for (int i = 0; i < P->count; i++)
{
printf("| %-4d | %-8s | %-2s | %-4.2f |\n",
P->students[i].id,
P->students[i].name,
P->students[i].gender,
P->students[i].score);
}
printf("------------------------------------------------------------\n");
}
5.从文件加载学生的信息,保存学生信息至文件
//
// 释放内容
void freeStudent(StudentList *P)
{
free(P->students);
P->students = NULL;
P->count = 0;
P->capacity = 0;
}
//
// 保存学生信息到文件
void saveStudentsToFile(StudentList *list, const char *filename)
{
FILE *file = fopen(filename, "wb");
if (!file)
{
printf("无法打开文件进行保存。\n");
return;
}
fwrite(list->students, sizeof(Student), list->count, file);
fclose(file);
printf("学生信息已保存到文件 %s\n", filename);
}
//
// 从文件加载学生信息
void loadStudentsFromFile(StudentList *list, const char *filename)
{
FILE *file = fopen(filename, "rb");
if (!file)
{
printf("无法打开文件进行加载。\n");
return;
}
// 先清空现有数据
// freeStudent(list);
// 尝试加载
size_t read = fread(list->students, sizeof(Student), list->capacity, file);
if (read > 0)
{
list->count = (int)read;
}
else
{
list->count = 0;
}
fclose(file);
printf("学生信息已从文件 %s 加载。\n", filename);
}
5.查找学生的信息
Search_stu函数提供了id和name两种方式查找学生的信息,由flag决定。遍历即可实现。
//
// 查找学生的信息,可使用id、name
int Search_stu(StudentList *P)
{
int flag = 0;
printf("使用学号id查询输入1, 使用姓名查询使用0: ");
scanf("%d", &flag);
if (flag) // 使用id经行查询
{
int new_id = 0;
printf("请输入学号id: ");
scanf("%d", &new_id);
for (int i = 0; i < P->count; i++)
{
if (P->students[i].id == new_id)
{
printf("| %-4d | %-8s | %-2s | %-4.2f |\n",
P->students[i].id,
P->students[i].name,
P->students[i].gender,
P->students[i].score);
return 0;
}
}
printf("无该学生的信息!\n");
return 0;
}
//
// 使用姓名查询
else
{
char new_name[20];
printf("请输入姓名name: ");
scanf("%s", &new_name);
for (int i = 0; i < P->count; i++)
{
if (strcmp(P->students[i].name, new_name) == 0)
{
printf("| %-4d | %-8s | %-2s | %-4.2f |\n",
P->students[i].id,
P->students[i].name,
P->students[i].gender,
P->students[i].score);
return 0;
}
}
printf("无该学生的信息!\n");
return 0;
}
}
6.统计学生的信息
该模块只提供了显示最高、最低成绩,平均成绩。感兴趣的同学可自行添加功能。
//
int max(int a, int b)
{
return (a > b) ? a : b;
}
//
int min(int a, int b)
{
return (a > b) ? b : a;
}
//
// 学生统计模块
void Student_information_statistics(StudentList *P)
{
if (P->count == 0)
{
printf("系统内无学生信息,无法统计");
return;
}
// 统计学生信息相关的统计量
float sum_score = 0, ave_score = 0, max_score = 0, min_score = 0;
for (size_t i = 0; i < P->count; i++)
{
sum_score += P->students[i].score;
max_score = max(P->students[i].score, max_score);
min_score = min(P->students[i].score, max_score);
}
ave_score = sum_score / P->count;
printf("学生的平均成绩:%-4.2f, 最高成绩: %4.2f, 最低成绩:%4.2f\n",
ave_score, max_score, min_score);
}
7.修改学生的信息
提供了两种方式:按学号id、name两种方式查找到某位同学,在进行信息修改,通过赋值即可。
// 修改学生信息
void modify_stu_information(StudentList *P)
{
if (P->count == 0)
{
printf("系统内无学生信息,无法修改");
return;
}
int modify_id = 0;
printf("请输入修改学生的学号id\n");
scanf("%d", &modify_id);
for (size_t i = 0; i < P->count; i++)
{
if (P->students[i].id == modify_id)
{
printf("要修改名字吗?[y/n]\n");
char modify_name;
scanf(" %c", &modify_name);
if (modify_name == 'y' || modify_name == 'Y')
{
printf("请输入新的姓名: ");
scanf("%s", &P->students[i].name);
printf("姓名已修改为: %s\n", P->students[i].name);
}
//
printf("要修改性别吗?[y/n]\n");
char modify_gender;
scanf(" %c", &modify_gender);
if (modify_gender == 'y' || modify_gender == 'Y')
{
printf("请输入新的性别: ");
scanf(" %s", &P->students[i].gender);
printf("性别已修改为: %s\n", P->students[i].gender);
}
//
printf("要修改分数吗?[y/n]\n");
char modify_score;
scanf(" %c", &modify_score);
if (modify_score == 'y' || modify_score == 'Y')
{
printf("请输入新的分数: ");
scanf("%f", &P->students[i].score);
printf("分数已修改为: %.2f\n", P->students[i].score);
}
return;
}
}
printf("未找到该学生!\n");
}
8.删除学生信息
/
// 删除学生信息
void delete_stu(StudentList *P)
{
if (P->count == 0)
{
printf("系统内无任何学生信息,无法删除!");
return;
}
printf("请输入想要删除的学生名字:");
char del_name[10];
scanf("%s", &del_name);
for (size_t i = 0; i < P->count; i++)
{
// 先找到name,然后将后面的list一个一个向前移
if (strcmp(del_name, P->students[i].name) == 0)
{
for (size_t j = i; j < P->count - 1; j++)
{
P->students[j] = P->students[j + 1];
}
P->count--;
printf("学生 %s 已删除。\n", del_name);
return;
}
}
printf("没有找到该学生!\n");
}
9.排序功能
/
// 按照学生成绩排序
void sort_students(int ascending, StudentList *P)
{
if (P->count <= 1)
{
return; // 如果学生数量为0或1,无需排序
}
Student temp;
for (int i = 0; i < P->count - 1; i++)
{
for (int j = 0; j < P->count - i - 1; j++)
{
// 根据ascending参数决定升序还是降序
if ((ascending && P->students[j].score > P->students[j + 1].score) ||
(!ascending && P->students[j].score < P->students[j + 1].score))
{
// 交换学生信息
temp = P->students[j];
P->students[j] = P->students[j + 1];
P->students[j + 1] = temp;
}
}
}
}
10.显示菜单功能
void showMenu()
{
printf("\n===== 学生信息管理系统 =====\n");
printf(" 1. 录入学生信息 \n");
printf(" 2. 显示所有学生信息 \n");
printf(" 3. 保存学生信息到文件 \n");
printf(" 4. 从文件加载学生信息 \n");
printf(" 5. 退出系统 \n");
printf(" 6. 查找学生信息 \n");
printf(" 7. 查询学生的统计信息 \n");
printf(" 8. 修改学生信息 \n");
printf(" 9. 删除学生信息 \n");
printf(" 10.排序");
printf("\n============================\n");
}
11.系统登录模块
采用明文储存,只用作学习使用。
/ 登录模块
#define MAX_ATTEMPTS 3 // 最大登录尝试次数
int passward_login()
{
char password[50]; // 存储用户输入的密码
int attempts = 0; // 登录尝试次数
const char *default_password = "123456"; // 默认密码
printf("正在登陆系统!\n");
while (attempts < MAX_ATTEMPTS)
{
printf("请输入学生管理系统的登录密码!第%d次登录: ", attempts + 1);
fgets(password, sizeof(password), stdin);
// 去掉换行符
password[strcspn(password, "\n")] = '\0';
if (strcmp(password, default_password) == 0)
{
printf("系统登录成功!\n");
return 0; // 登录成功,退出程序
}
else
{
printf("系统登录失败!请重新输入密码。\n");
attempts++;
}
}
printf("密码输入错误次数过多,退出系统!\n");
return 1; // 登录失败,退出程序
}
//
12.main函数
首先建立了一个StudentList类,初始化容量为10,尝试加载之前保存的学生信息;
循环里面主要是操作选择,对应之前的函数功能。
int main()
{
// passward_login();
StudentList list;
InitStudentList(&list, 10); // 初始容量为10
// 尝试加载之前保存的学生信息
loadStudentsFromFile(&list, "students.dat");
int choice;
const char *filename = "students.dat"; // 学生信息存储文件
while (1)
{
showMenu();
printf("请选操作: ");
scanf("%d", &choice);
switch (choice)
{
case 1:
AddStudentList(&list);
break;
case 2:
displayStudent(&list);
break;
case 3:
saveStudentsToFile(&list, filename);
break;
case 4:
loadStudentsFromFile(&list, filename);
break;
case 5:
saveStudentsToFile(&list, filename); // 确保退出前保存最新数据
freeStudent(&list);
printf("已退出系统。\n");
return 0;
case 6:
Search_stu(&list);
break;
case 7:
Student_information_statistics(&list);
break;
case 8:
modify_stu_information(&list);
break;
case 9:
delete_stu(&list);
break;
case 10:
printf("降序输入:0,升序输入:1\n");
int ascending = 0;
scanf("%d", &ascending);
sort_students(ascending, &list);
printf("排序后的学生列表为:");
displayStudent(&list);
break;
default:
printf("无效的选择,请重新选择。\n");
}
}
return 0;
}