Add files via upload

This commit is contained in:
2025-07-12 23:33:14 +08:00
committed by GitHub
parent 8c44e5f2f7
commit 73a396a9d9
20 changed files with 2652 additions and 0 deletions
+72
View File
@@ -0,0 +1,72 @@
# 学生成绩管理系统 Makefile
# 编译器设置
CC = gcc
CFLAGS = -Wall -Wextra -std=c99 -g
# 目标文件
TARGET = student_system
# 源文件
SOURCES = main.c globals.c auxiliary.c main_menu.c user_manage.c stu_data.c statistical_analysis.c
# 目标文件
OBJECTS = $(SOURCES:.c=.o)
# 头文件
HEADERS = config.h globals.h auxiliary.h main_menu.h user_manage.h stu.data.h statistical_analysis.h
# 默认目标
all: $(TARGET)
# 链接目标文件
$(TARGET): $(OBJECTS)
$(CC) $(OBJECTS) -o $(TARGET)
# 编译源文件
%.o: %.c $(HEADERS)
$(CC) $(CFLAGS) -c $< -o $@
# 清理编译文件
clean:
rm -f $(OBJECTS) $(TARGET)
rm -f *.exe
# 创建必要的目录
setup:
mkdir -p data
mkdir -p backup
# 运行程序
run: $(TARGET)
./$(TARGET)
# Windows 特定目标
windows: CFLAGS += -DWINDOWS
windows: $(TARGET)
# 调试版本
debug: CFLAGS += -DDEBUG -O0
debug: $(TARGET)
# 发布版本
release: CFLAGS += -O2 -DNDEBUG
release: $(TARGET)
# 安装(可选)
install: $(TARGET)
cp $(TARGET) /usr/local/bin/
# 帮助信息
help:
@echo "可用的目标:"
@echo " all - 编译程序(默认)"
@echo " clean - 清理编译文件"
@echo " setup - 创建必要的目录"
@echo " run - 编译并运行程序"
@echo " windows - 编译Windows版本"
@echo " debug - 编译调试版本"
@echo " release - 编译发布版本"
@echo " install - 安装程序到系统"
@echo " help - 显示此帮助信息"
.PHONY: all clean setup run windows debug release install help
+449
View File
@@ -0,0 +1,449 @@
/**
* @file auxiliary.c
* @brief 辅助函数实现文件
* @note 实现系统中使用的各种辅助函数
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <errno.h>
#ifdef _WIN32
#include <windows.h>
#include <direct.h>
#include <conio.h>
#else
#include <sys/stat.h>
#include <unistd.h>
#include <termios.h>
#endif
#include "auxiliary.h"
#include "config.h"
#include "globals.h"
#include "stu.data.h"
#include "user_manage.h"
/**
* @brief 清理输入缓冲区
*/
void clearInputBuffer()
{
int c;
while ((c = getchar()) != '\n' && c != EOF)
;
}
/**
* @brief 暂停系统,等待用户按键
*/
void pauseSystem()
{
printf("\n按任意键继续...");
#ifdef _WIN32
_getch();
#else
getchar();
#endif
printf("\n");
}
/**
* @brief 清屏
*/
void clearScreen()
{
#ifdef _WIN32
system("cls");
#else
system("clear");
#endif
}
/**
* @brief 打印分隔线
*/
void printSeparator()
{
printf("========================================\n");
}
/**
* @brief 打印标题头
* @param title 标题文本
*/
void printHeader(const char *title)
{
printSeparator();
printf(" %s\n", title);
printSeparator();
}
/**
* @brief 验证分数是否合法
* @param score 分数
* @return 合法返回true,否则返回false
*/
bool isValidScore(float score)
{
return score >= MIN_SCORE && score <= MAX_SCORE;
}
/**
* @brief 验证学号格式
* @param id 学号
* @return 合法返回true,否则返回false
*/
bool isValidStudentID(const char *id)
{
if (id == NULL || strlen(id) == 0 || strlen(id) >= MAX_ID_LENGTH)
{
return false;
}
// 检查是否只包含数字和字母
for (int i = 0; id[i] != '\0'; i++)
{
if (!isalnum(id[i]))
{
return false;
}
}
return true;
}
/**
* @brief 验证姓名格式
* @param name 姓名
* @return 合法返回true,否则返回false
*/
bool isValidName(const char *name)
{
if (name == NULL || strlen(name) == 0 || strlen(name) >= MAX_NAME_LENGTH)
{
return false;
}
// 检查是否包含非法字符
for (int i = 0; name[i] != '\0'; i++)
{
if (!isalpha(name[i]) && name[i] != ' ' && name[i] != '-' &&
(unsigned char)name[i] < 128)
{ // 允许中文字符
return false;
}
}
return true;
}
/**
* @brief 验证性别
* @param gender 性别字符
* @return 合法返回true,否则返回false
*/
bool isValidGender(char gender)
{
return gender == GENDER_MALE || gender == GENDER_FEMALE;
}
/**
* @brief 验证年龄
* @param age 年龄
* @return 合法返回true,否则返回false
*/
bool isValidAge(int age)
{
return age >= 10 && age <= 100;
}
/**
* @brief 去除字符串首尾空格
* @param str 字符串
*/
void trimString(char *str)
{
if (str == NULL)
return;
// 去除开头空格
char *start = str;
while (isspace(*start))
start++;
// 去除结尾空格
char *end = str + strlen(str) - 1;
while (end > start && isspace(*end))
end--;
// 移动字符串
int len = end - start + 1;
memmove(str, start, len);
str[len] = '\0';
}
/**
* @brief 判断字符串是否为空
* @param str 字符串
* @return 为空返回true,否则返回false
*/
bool isEmptyString(const char *str)
{
if (str == NULL)
return true;
while (*str)
{
if (!isspace(*str))
return false;
str++;
}
return true;
}
/**
* @brief 检查文件是否存在
* @param filename 文件名
* @return 存在返回true,否则返回false
*/
bool fileExists(const char *filename)
{
FILE *file = fopen(filename, "r");
if (file)
{
fclose(file);
return true;
}
return false;
}
/**
* @brief 创建目录
* @param path 目录路径
* @return 成功返回true,否则返回false
*/
bool createDirectory(const char *path)
{
#ifdef _WIN32
return _mkdir(path) == 0 || errno == EEXIST;
#else
return mkdir(path, 0755) == 0 || errno == EEXIST;
#endif
}
/**
* @brief 计算平均分
* @param scores 分数数组
* @param count 分数个数
* @return 平均分
*/
float calculateAverage(float scores[], int count)
{
if (count <= 0)
return 0.0;
float sum = 0.0;
for (int i = 0; i < count; i++)
{
sum += scores[i];
}
return sum / count;
}
/**
* @brief 安全输入整数
* @param prompt 提示信息
* @param min 最小值
* @param max 最大值
* @return 输入的整数
*/
int safeInputInt(const char *prompt, int min, int max)
{
int value;
char buffer[100];
while (1)
{
printf("%s (%d-%d): ", prompt, min, max);
if (fgets(buffer, sizeof(buffer), stdin) != NULL)
{
if (sscanf(buffer, "%d", &value) == 1)
{
if (value >= min && value <= max)
{
return value;
}
}
}
printError("输入无效,请重新输入!");
}
}
/**
* @brief 安全输入浮点数
* @param prompt 提示信息
* @param min 最小值
* @param max 最大值
* @return 输入的浮点数
*/
float safeInputFloat(const char *prompt, float min, float max)
{
float value;
char buffer[100];
while (1)
{
printf("%s (%.1f-%.1f): ", prompt, min, max);
if (fgets(buffer, sizeof(buffer), stdin) != NULL)
{
if (sscanf(buffer, "%f", &value) == 1)
{
if (value >= min && value <= max)
{
return value;
}
}
}
printError("输入无效,请重新输入!");
}
}
/**
* @brief 安全输入字符串
* @param prompt 提示信息
* @param buffer 缓冲区
* @param maxLen 最大长度
*/
void safeInputString(const char *prompt, char *buffer, int maxLen)
{
while (1)
{
printf("%s: ", prompt);
if (fgets(buffer, maxLen, stdin) != NULL)
{
// 移除换行符
buffer[strcspn(buffer, "\n")] = '\0';
trimString(buffer);
if (!isEmptyString(buffer))
{
return;
}
}
printError("输入不能为空,请重新输入!");
}
}
/**
* @brief 彩色输出
* @param text 文本
* @param color 颜色代码
*/
void printColored(const char *text, const char *color)
{
printf("%s%s%s", color, text, COLOR_RESET);
}
/**
* @brief 成功消息
* @param message 消息
*/
void printSuccess(const char *message)
{
printColored(message, COLOR_GREEN);
printf("\n");
}
/**
* @brief 错误消息
* @param message 消息
*/
void printError(const char *message)
{
printColored(message, COLOR_RED);
printf("\n");
}
/**
* @brief 警告消息
* @param message 消息
*/
void printWarning(const char *message)
{
printColored(message, COLOR_YELLOW);
printf("\n");
}
/**
* @brief 信息消息
* @param message 消息
*/
void printInfo(const char *message)
{
printColored(message, COLOR_CYAN);
printf("\n");
}
/**
* @brief 初始化系统
* @return 成功返回true,否则返回false
*/
bool initializeSystem()
{
// 创建数据目录
if (!createDataDirectories())
{
return false;
}
// 加载用户数据
loadUsersFromFile();
// 加载学生数据
loadStudentsFromFile();
systemInitialized = true;
return true;
}
/**
* @brief 创建数据目录
* @return 成功返回true,否则返回false
*/
bool createDataDirectories()
{
if (!createDirectory("data"))
{
return false;
}
if (!createDirectory(BACKUP_DIR))
{
return false;
}
return true;
}
/**
* @brief 清理系统资源
*/
void cleanupSystem()
{
// 保存数据
if (dataModified)
{
saveStudentsToFile();
saveUsersToFile();
}
systemInitialized = false;
}
+62
View File
@@ -0,0 +1,62 @@
/**
* @file auxiliary.h
* @brief 辅助函数头文件
* @note 包含系统中使用的各种辅助函数声明
*/
#ifndef AUXILIARY_H
#define AUXILIARY_H
#include <stdbool.h>
#include "main_menu.h"
// 输入输出辅助函数
void clearInputBuffer(); // 清理输入缓冲区
void pauseSystem(); // 暂停系统,等待用户按键
void clearScreen(); // 清屏
void printSeparator(); // 打印分隔线
void printHeader(const char* title); // 打印标题头
// 数据验证函数
bool isValidScore(float score); // 验证分数是否合法 (0-100)
bool isValidStudentID(const char* id); // 验证学号格式
bool isValidName(const char* name); // 验证姓名格式
bool isValidGender(char gender); // 验证性别
bool isValidAge(int age); // 验证年龄
// 字符串处理函数
void trimString(char* str); // 去除字符串首尾空格
bool isEmptyString(const char* str); // 判断字符串是否为空
void toLowerCase(char* str); // 转换为小写
void toUpperCase(char* str); // 转换为大写
// 文件操作辅助函数
bool fileExists(const char* filename); // 检查文件是否存在
bool createDirectory(const char* path); // 创建目录
bool backupFile(const char* source, const char* backup); // 备份文件
// 数学计算辅助函数
float calculateAverage(float scores[], int count); // 计算平均分
float findMaxScore(float scores[], int count); // 找最高分
float findMinScore(float scores[], int count); // 找最低分
// 安全输入函数
int safeInputInt(const char* prompt, int min, int max); // 安全输入整数
float safeInputFloat(const char* prompt, float min, float max); // 安全输入浮点数
void safeInputString(const char* prompt, char* buffer, int maxLen); // 安全输入字符串
char safeInputChar(const char* prompt, const char* validChars); // 安全输入字符
// 系统初始化和清理函数
bool initializeSystem(); // 初始化系统
void cleanupSystem(); // 清理系统资源
bool createDataDirectories(); // 创建数据目录
// 颜色输出函数
void printColored(const char* text, const char* color); // 彩色输出
void printSuccess(const char* message); // 成功消息
void printError(const char* message); // 错误消息
void printWarning(const char* message); // 警告消息
void printInfo(const char* message); // 信息消息
#endif // AUXILIARY_H
+108
View File
@@ -0,0 +1,108 @@
/**
* @file config.h
* @brief 学生成绩管理系统参数配置头文件
* @note 本文件集中定义了学生成绩管理系统的所有参数配置,便于统一管理和修改
*/
#ifndef CONFIG_H
#define CONFIG_H
// 系统配置参数
#define MAX_STUDENTS 1000 // 最大学生数量
#define MAX_COURSES 10 // 每个学生最多课程数
#define MAX_USERS 50 // 最大用户数量
#define MAX_LOGIN_ATTEMPTS 3 // 最大登录尝试次数
// 字符串长度限制
#define MAX_ID_LENGTH 20 // 学号最大长度
#define MAX_NAME_LENGTH 50 // 姓名最大长度
#define MAX_COURSE_NAME_LENGTH 50 // 课程名称最大长度
#define MAX_USERNAME_LENGTH 30 // 用户名最大长度
#define MAX_PASSWORD_LENGTH 30 // 密码最大长度
// 分数相关配置
#define MIN_SCORE 0.0 // 最低分数
#define MAX_SCORE 100.0 // 最高分数
#define PASS_SCORE 60.0 // 及格分数
#define EXCELLENT_SCORE 90.0 // 优秀分数
// 文件路径配置
#define STUDENTS_FILE "data/students.csv" // 学生数据文件
#define USERS_FILE "data/users.txt" // 用户数据文件
#define BACKUP_DIR "backup/" // 备份目录
// 菜单选项定义
#define MENU_EXIT 0
#define MENU_BASIC_FUNCTIONS 1
#define MENU_STATISTICS 2
#define MENU_ADMIN 3
// 基本功能菜单选项
#define BASIC_BACK 0
#define BASIC_ADD_STUDENT 1
#define BASIC_DELETE_STUDENT 2
#define BASIC_MODIFY_STUDENT 3
#define BASIC_SEARCH_BY_ID 4
#define BASIC_SEARCH_BY_NAME 5
#define BASIC_DISPLAY_ALL 6
#define BASIC_SORT_STUDENTS 7
// 统计功能菜单选项
#define STATS_BACK 0
#define STATS_COURSE_ANALYSIS 1
#define STATS_SCORE_DISTRIBUTION 2
#define STATS_SCORE_RANGES 3
#define STATS_OVERALL_ANALYSIS 4
// 管理功能菜单选项
#define ADMIN_BACK 0
#define ADMIN_ADD_USER 1
#define ADMIN_DELETE_USER 2
#define ADMIN_MODIFY_PASSWORD 3
#define ADMIN_VIEW_USERS 4
// 排序选项
#define SORT_BY_ID 1
#define SORT_BY_NAME 2
#define SORT_BY_TOTAL_SCORE 3
#define SORT_BY_AVERAGE_SCORE 4
// 排序顺序
#define SORT_ASCENDING 1
#define SORT_DESCENDING 2
// 性别定义
#define GENDER_MALE 'M'
#define GENDER_FEMALE 'F'
// 颜色代码(用于美化输出)
#define COLOR_RESET "\033[0m"
#define COLOR_RED "\033[31m"
#define COLOR_GREEN "\033[32m"
#define COLOR_YELLOW "\033[33m"
#define COLOR_BLUE "\033[34m"
#define COLOR_MAGENTA "\033[35m"
#define COLOR_CYAN "\033[36m"
#define COLOR_WHITE "\033[37m"
// 系统消息
#define MSG_SUCCESS "操作成功!"
#define MSG_FAILURE "操作失败!"
#define MSG_NOT_FOUND "未找到相关记录!"
#define MSG_INVALID_INPUT "输入无效,请重新输入!"
#define MSG_FILE_ERROR "文件操作错误!"
// 数据结构定义
typedef struct {
char studentID[MAX_ID_LENGTH]; // 学号
char name[MAX_NAME_LENGTH]; // 姓名
int age; // 年龄
char gender; // 性别 ('M'/'F')
char courses[MAX_COURSES][MAX_COURSE_NAME_LENGTH]; // 课程名称
float scores[MAX_COURSES]; // 各科成绩
int courseCount; // 课程数量
float totalScore; // 总分
float averageScore; // 平均分
} Student;
#endif // CONFIG_H
+154
View File
@@ -0,0 +1,154 @@
/**
* @file core_handlers.c
* @brief 核心处理函数实现文件
* @note 实现主要的功能处理函数
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "core_handlers.h"
#include "config.h"
#include "globals.h"
#include "main_menu.h"
#include "user_manage.h"
#include "stu.data.h"
#include "statistical_analysis.h"
#include "auxiliary.h"
/**
* @brief 处理基本功能菜单
*/
void handleBasicFunctions()
{
int choice;
do {
clearScreen();
displayBasicFunctionsMenu();
choice = safeInputInt("请选择功能", BASIC_BACK, BASIC_SORT_STUDENTS);
switch (choice) {
case BASIC_ADD_STUDENT:
addStudent();
break;
case BASIC_DELETE_STUDENT:
deleteStudent();
break;
case BASIC_MODIFY_STUDENT:
modifyStudent();
break;
case BASIC_SEARCH_BY_ID:
searchStudentByID();
break;
case BASIC_SEARCH_BY_NAME:
searchStudentByName();
break;
case BASIC_DISPLAY_ALL:
displayAllStudents();
break;
case BASIC_SORT_STUDENTS:
handleSortStudents();
break;
case BASIC_BACK:
break;
default:
printError("无效的选择!");
pauseSystem();
break;
}
} while (choice != BASIC_BACK);
}
/**
* @brief 处理统计功能菜单
*/
void handleStatistics() {
int choice;
do {
clearScreen();
displayStatisticsMenu();
choice = safeInputInt("请选择功能", STATS_BACK, STATS_OVERALL_ANALYSIS);
switch (choice) {
case STATS_COURSE_ANALYSIS:
displayCourseStatistics();
break;
case STATS_SCORE_DISTRIBUTION:
displayScoreDistribution();
break;
case STATS_SCORE_RANGES:
displayStudentRanking();
break;
case STATS_OVERALL_ANALYSIS:
displayOverallStatistics();
break;
case STATS_BACK:
break;
default:
printError("无效的选择!");
pauseSystem();
break;
}
} while (choice != STATS_BACK);
}
/**
* @brief 处理管理功能菜单
*/
void handleAdminFunctions() {
int choice;
do {
clearScreen();
displayAdminMenu();
choice = safeInputInt("请选择功能", ADMIN_BACK, ADMIN_VIEW_USERS);
switch (choice) {
case ADMIN_ADD_USER:
addUserAccount();
break;
case ADMIN_DELETE_USER:
deleteUserAccount();
break;
case ADMIN_MODIFY_PASSWORD:
modifyUserPassword();
break;
case ADMIN_VIEW_USERS:
viewAllUsers();
break;
case ADMIN_BACK:
break;
default:
printError("无效的选择!");
pauseSystem();
break;
}
} while (choice != ADMIN_BACK);
}
/**
* @brief 处理学生排序功能
*/
void handleSortStudents() {
clearScreen();
printHeader("学生排序");
printf("排序依据:\n");
printf("1. 按学号排序\n");
printf("2. 按姓名排序\n");
printf("3. 按总分排序\n");
printf("4. 按平均分排序\n");
int criteria = safeInputInt("请选择排序依据", SORT_BY_ID, SORT_BY_AVERAGE_SCORE);
printf("\n排序顺序:\n");
printf("1. 升序\n");
printf("2. 降序\n");
int order = safeInputInt("请选择排序顺序", SORT_ASCENDING, SORT_DESCENDING);
sortStudents(criteria, order);
printf("\n排序完成!\n");
displayAllStudents();
}
+18
View File
@@ -0,0 +1,18 @@
/**
* @file core_handlers.h
* @brief 核心处理函数头文件
* @note 包含主要的功能处理函数声明
*/
#ifndef CORE_HANDLERS_H
#define CORE_HANDLERS_H
#include "config.h"
// 核心处理函数声明
void handleBasicFunctions(); // 处理基本功能菜单
void handleStatistics(); // 处理统计功能菜单
void handleAdminFunctions(); // 处理管理功能菜单
void handleSortStudents(); // 处理学生排序功能
#endif // CORE_HANDLERS_H
+25
View File
@@ -0,0 +1,25 @@
/**
* @file globals.c
* @brief 全局变量定义文件
* @note 定义所有全局变量的实际存储空间
*/
#include "globals.h"
// 全局变量定义
Student students[MAX_STUDENTS]; // 学生数组
User users[MAX_USERS]; // 用户数组
int studentCount = 0; // 当前学生数量
int userCount = 0; // 当前用户数量
char currentUser[MAX_USERNAME_LENGTH] = ""; // 当前登录用户
bool isCurrentUserAdmin = false; // 当前用户是否为管理员
// 系统状态变量
bool systemInitialized = false; // 系统是否已初始化
bool dataModified = false; // 数据是否已修改
// 统计信息缓存
float overallAverageScore = 0.0; // 全体学生平均分
float highestScore = 0.0; // 最高分
float lowestScore = 100.0; // 最低分
bool statsNeedUpdate = true; // 统计信息是否需要更新
+39
View File
@@ -0,0 +1,39 @@
/**
* @file globals.h
* @brief 全局变量声明头文件
* @note 集中管理所有全局变量的声明,提高代码可维护性
*/
#ifndef GLOBALS_H
#define GLOBALS_H
#include <stdbool.h>
#include "config.h"
#include "main_menu.h"
// 用户结构体定义
typedef struct {
char username[MAX_USERNAME_LENGTH];
char password[MAX_PASSWORD_LENGTH];
bool isAdmin; // 是否为管理员
} User;
// 全局变量声明
extern Student students[MAX_STUDENTS]; // 学生数组
extern User users[MAX_USERS]; // 用户数组
extern int studentCount; // 当前学生数量
extern int userCount; // 当前用户数量
extern char currentUser[MAX_USERNAME_LENGTH]; // 当前登录用户
extern bool isCurrentUserAdmin; // 当前用户是否为管理员
// 系统状态变量
extern bool systemInitialized; // 系统是否已初始化
extern bool dataModified; // 数据是否已修改(用于判断是否需要保存)
// 统计信息缓存(可选,用于提高性能)
extern float overallAverageScore; // 全体学生平均分
extern float highestScore; // 最高分
extern float lowestScore; // 最低分
extern bool statsNeedUpdate; // 统计信息是否需要更新
#endif // GLOBALS_H
+146
View File
@@ -0,0 +1,146 @@
/**
* @file main.c
* @brief 学生成绩管理系统主程序
* @note 系统入口点,包含主要的程序流程控制
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#ifdef _WIN32
#include <windows.h>
#include <direct.h>
#else
#include <sys/stat.h>
#include <unistd.h>
#endif
#include "config.h"
#include "globals.h"
#include "main_menu.h"
#include "user_manage.h"
#include "stu.data.h"
#include "statistical_analysis.h"
#include "auxiliary.h"
#include "core_handlers.h"
/**
* @brief 主程序入口
* @param argc 命令行参数个数
* @param argv 命令行参数数组
* @return 程序退出状态码
* @note 系统中有两个用户:
1. admin - 密码是 123456
2. teacher - 密码是 password
* @note
gcc -o student_system.exe main.c stu_data.c auxiliary.c statistical_analysis.c main_menu.c globals.c user_manage.c core_handlers.c
.\student_system.exe
*/
int main(int argc, char *argv[])
{
// 设置控制台编码为UTF-8
#ifdef _WIN32
system("chcp 65001 > nul"); // 设置控制台编码为UTF-8
SetConsoleOutputCP(65001); // 设置控制台输出编码
SetConsoleCP(65001); // 设置控制台输入编码
#endif
// 初始化系统
if (!initializeSystem())
{
printError("系统初始化失败!");
return -1;
}
// 显示欢迎信息
clearScreen();
printHeader("学生成绩管理系统");
printf("\n");
printInfo("欢迎使用学生成绩管理系统!");
printf("\n");
pauseSystem();
// 用户登录
int loginAttempts = 0;
while (loginAttempts < MAX_LOGIN_ATTEMPTS)
{
clearScreen();
printHeader("用户登录");
if (loginSystem())
{
printSuccess("登录成功!");
printf("欢迎您,%s%s\n", currentUser,
isCurrentUserAdmin ? " (管理员)" : " (普通用户)");
pauseSystem();
break;
}
else
{
loginAttempts++;
if (loginAttempts < MAX_LOGIN_ATTEMPTS)
{
printError("登录失败!请检查用户名和密码。");
printf("剩余尝试次数:%d\n", MAX_LOGIN_ATTEMPTS - loginAttempts);
pauseSystem();
}
}
}
// 登录失败次数过多,退出程序
if (loginAttempts >= MAX_LOGIN_ATTEMPTS)
{
printError("登录失败次数过多,程序将退出!");
cleanupSystem();
return -1;
}
// 主程序循环
int choice;
do
{
clearScreen();
displayMainMenu();
choice = safeInputInt("请选择功能", MENU_EXIT, MENU_ADMIN);
switch (choice)
{
case MENU_BASIC_FUNCTIONS:
handleBasicFunctions();
break;
case MENU_STATISTICS:
handleStatistics();
break;
case MENU_ADMIN:
if (isCurrentUserAdmin)
{
handleAdminFunctions();
}
else
{
printError("您没有管理员权限!");
pauseSystem();
}
break;
case MENU_EXIT:
// 保存数据并退出
if (dataModified)
{
printInfo("正在保存数据...");
saveStudentsToFile();
saveUsersToFile();
printSuccess("数据保存完成!");
}
printInfo("感谢使用学生成绩管理系统!");
break;
default:
printError("无效的选择!");
pauseSystem();
break;
}
} while (choice != MENU_EXIT);
// 清理系统资源
cleanupSystem();
return 0;
}
+92
View File
@@ -0,0 +1,92 @@
/**
* @file main_menu.c
* @brief 主菜单实现文件
* @note 实现各种菜单显示功能
*/
#include <stdio.h>
#include "main_menu.h"
#include "config.h"
#include "auxiliary.h"
#include "globals.h"
/**
* @brief 显示主菜单
*/
void displayMainMenu()
{
printHeader("学生成绩管理系统 - 主菜单");
printf("\n");
printf("当前用户: %s %s\n", currentUser,
isCurrentUserAdmin ? "(管理员)" : "(普通用户)");
printf("\n");
printf("1. 基本功能管理\n");
printf("2. 统计分析功能\n");
if (isCurrentUserAdmin)
{
printf("3. 系统管理功能\n");
}
printf("0. 退出系统\n");
printf("\n");
printSeparator();
}
/**
* @brief 显示基本功能菜单
*/
void displayBasicFunctionsMenu()
{
printHeader("基本功能管理");
printf("\n");
printf("1. 添加学生信息\n");
printf("2. 删除学生信息\n");
printf("3. 修改学生信息\n");
printf("4. 按学号查找学生\n");
printf("5. 按姓名查找学生\n");
printf("6. 显示所有学生\n");
printf("7. 学生信息排序\n");
printf("0. 返回主菜单\n");
printf("\n");
printf("当前学生总数: %d\n", studentCount);
printf("\n");
printSeparator();
}
/**
* @brief 显示统计功能菜单
*/
void displayStatisticsMenu()
{
printHeader("统计分析功能");
printf("\n");
printf("1. 课程统计分析\n");
printf("2. 成绩分布统计\n");
printf("3. 分数段统计\n");
printf("4. 综合统计分析\n");
printf("0. 返回主菜单\n");
printf("\n");
printf("当前学生总数: %d\n", studentCount);
if (studentCount > 0) {
printf("系统平均分: %.2f\n", overallAverageScore);
}
printf("\n");
printSeparator();
}
/**
* @brief 显示管理功能菜单
*/
void displayAdminMenu()
{
printHeader("系统管理功能");
printf("\n");
printf("1. 添加用户账户\n");
printf("2. 删除用户账户\n");
printf("3. 修改用户密码\n");
printf("4. 查看所有用户\n");
printf("0. 返回主菜单\n");
printf("\n");
printf("当前用户总数: %d\n", userCount);
printf("\n");
printSeparator();
}
+12
View File
@@ -0,0 +1,12 @@
#ifndef MAIN_MENU_H
#define MAIN_MENU_H
#include "config.h"
// 主菜单和子菜单显示函数
void displayMainMenu(); // 显示主菜单
void displayBasicFunctionsMenu(); // 显示基本功能菜单
void displayStatisticsMenu(); // 显示统计功能菜单
void displayAdminMenu(); // 显示管理功能菜单
#endif // MAIN_MENU_H
+488
View File
@@ -0,0 +1,488 @@
/**
* @file statistical_analysis.c
* @brief 统计分析功能实现文件
* @note 实现各种统计分析功能
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include "statistical_analysis.h"
#include "config.h"
#include "globals.h"
#include "auxiliary.h"
#include "stu.data.h"
/**
* @brief 显示课程统计信息
*/
void displayCourseStatistics()
{
clearScreen();
printHeader("课程统计信息");
if (studentCount == 0)
{
printWarning("暂无学生数据!");
pauseSystem();
return;
}
// 收集所有课程名称
char courses[MAX_STUDENTS * MAX_COURSES][MAX_COURSE_NAME_LENGTH];
int courseCount = 0;
for (int i = 0; i < studentCount; i++) {
for (int j = 0; j < students[i].courseCount; j++) {
bool exists = false;
for (int k = 0; k < courseCount; k++) {
if (strcmp(courses[k], students[i].courses[j]) == 0) {
exists = true;
break;
}
}
if (!exists) {
strcpy(courses[courseCount], students[i].courses[j]);
courseCount++;
}
}
}
if (courseCount == 0) {
printWarning("暂无课程数据!");
pauseSystem();
return;
}
printf("\n");
printf("%-20s %-8s %-8s %-8s %-8s %-8s\n",
"课程名称", "人数", "最高分", "最低分", "平均分", "及格率");
printSeparator();
for (int i = 0; i < courseCount; i++) {
CourseStats stats = calculateCourseStats(courses[i]);
printf("%-20s %-8d %-8.2f %-8.2f %-8.2f %-8.2f%%\n",
courses[i], stats.studentCount, stats.maxScore,
stats.minScore, stats.averageScore, stats.passRate);
}
pauseSystem();
}
/**
* @brief 计算课程统计信息
*/
CourseStats calculateCourseStats(const char* courseName) {
CourseStats stats = {0};
float scores[MAX_STUDENTS];
int count = 0;
// 收集该课程的所有分数
for (int i = 0; i < studentCount; i++) {
for (int j = 0; j < students[i].courseCount; j++) {
if (strcmp(students[i].courses[j], courseName) == 0) {
scores[count] = students[i].scores[j];
count++;
break;
}
}
}
if (count == 0) return stats;
stats.studentCount = count;
stats.maxScore = scores[0];
stats.minScore = scores[0];
stats.totalScore = 0;
int passCount = 0;
for (int i = 0; i < count; i++) {
if (scores[i] > stats.maxScore) stats.maxScore = scores[i];
if (scores[i] < stats.minScore) stats.minScore = scores[i];
stats.totalScore += scores[i];
if (scores[i] >= PASS_SCORE) passCount++;
}
stats.averageScore = stats.totalScore / count;
stats.passRate = (float)passCount / count * 100;
return stats;
}
/**
* @brief 显示分数分布
*/
void displayScoreDistribution() {
clearScreen();
printHeader("分数分布统计");
if (studentCount == 0) {
printWarning("暂无学生数据!");
pauseSystem();
return;
}
ScoreDistribution dist = calculateScoreDistribution();
printf("\n分数段分布:\n");
printSeparator();
printf("90-100分: %d人 (%.2f%%)\n", dist.excellent,
(float)dist.excellent / studentCount * 100);
printf("80-89分: %d人 (%.2f%%)\n", dist.good,
(float)dist.good / studentCount * 100);
printf("70-79分: %d人 (%.2f%%)\n", dist.medium,
(float)dist.medium / studentCount * 100);
printf("60-69分: %d人 (%.2f%%)\n", dist.pass,
(float)dist.pass / studentCount * 100);
printf("0-59分: %d人 (%.2f%%)\n", dist.fail,
(float)dist.fail / studentCount * 100);
printf("\n总体统计:\n");
printf("总人数: %d\n", studentCount);
printf("及格人数: %d (%.2f%%)\n",
studentCount - dist.fail,
(float)(studentCount - dist.fail) / studentCount * 100);
printf("不及格人数: %d (%.2f%%)\n",
dist.fail, (float)dist.fail / studentCount * 100);
pauseSystem();
}
/**
* @brief 计算分数分布
*/
ScoreDistribution calculateScoreDistribution() {
ScoreDistribution dist = {0};
for (int i = 0; i < studentCount; i++) {
float avgScore = students[i].averageScore;
if (avgScore >= 90) {
dist.excellent++;
} else if (avgScore >= 80) {
dist.good++;
} else if (avgScore >= 70) {
dist.medium++;
} else if (avgScore >= 60) {
dist.pass++;
} else {
dist.fail++;
}
}
return dist;
}
/**
* @brief 显示学生排名
*/
void displayStudentRanking() {
clearScreen();
printHeader("学生排名");
if (studentCount == 0) {
printWarning("暂无学生数据!");
pauseSystem();
return;
}
// 创建排名数组
StudentRank rankings[MAX_STUDENTS];
for (int i = 0; i < studentCount; i++) {
rankings[i].studentIndex = i;
rankings[i].averageScore = students[i].averageScore;
rankings[i].totalScore = students[i].totalScore;
}
// 按平均分排序(降序)
for (int i = 0; i < studentCount - 1; i++) {
for (int j = 0; j < studentCount - 1 - i; j++) {
if (rankings[j].averageScore < rankings[j + 1].averageScore) {
StudentRank temp = rankings[j];
rankings[j] = rankings[j + 1];
rankings[j + 1] = temp;
}
}
}
printf("\n");
// 调整中文表头的对齐格式,考虑中文字符的显示宽度
printf("%-5s %-10s %-12s %-8s %-8s\n",
"排名", "学号", "姓名", "总分", "平均分");
printf("========================================\n");
for (int i = 0; i < studentCount; i++) {
int idx = rankings[i].studentIndex;
printf("%-5d %-10s %-12s %-8.2f %-8.2f\n",
i + 1,
students[idx].studentID,
students[idx].name,
students[idx].totalScore,
students[idx].averageScore);
}
pauseSystem();
}
/**
* @brief 显示系统总体统计
*/
void displayOverallStatistics() {
clearScreen();
printHeader("系统总体统计");
if (studentCount == 0) {
printWarning("暂无学生数据!");
pauseSystem();
return;
}
OverallStats stats = calculateOverallStats();
printf("\n学生信息统计:\n");
printSeparator();
printf("总学生数: %d\n", stats.totalStudents);
printf("男学生数: %d (%.2f%%)\n", stats.maleCount,
(float)stats.maleCount / stats.totalStudents * 100);
printf("女学生数: %d (%.2f%%)\n", stats.femaleCount,
(float)stats.femaleCount / stats.totalStudents * 100);
printf("平均年龄: %.1f岁\n", stats.averageAge);
printf("\n成绩统计:\n");
printSeparator();
printf("最高平均分: %.2f\n", stats.highestAverage);
printf("最低平均分: %.2f\n", stats.lowestAverage);
printf("全体平均分: %.2f\n", stats.overallAverageScore);
printf("标准差: %.2f\n", stats.standardDeviation);
printf("\n课程统计:\n");
printSeparator();
printf("总课程数: %d\n", stats.totalCourses);
printf("平均课程数/人: %.1f\n", stats.averageCoursesPerStudent);
pauseSystem();
}
/**
* @brief 计算系统总体统计
*/
OverallStats calculateOverallStats() {
OverallStats stats = {0};
if (studentCount == 0) return stats;
stats.totalStudents = studentCount;
float totalAge = 0;
float totalAverage = 0;
int totalCourseCount = 0;
// 收集所有课程名称
char courses[MAX_STUDENTS * MAX_COURSES][MAX_COURSE_NAME_LENGTH];
int uniqueCourseCount = 0;
stats.highestAverage = students[0].averageScore;
stats.lowestAverage = students[0].averageScore;
for (int i = 0; i < studentCount; i++) {
// 性别统计
if (students[i].gender == GENDER_MALE) {
stats.maleCount++;
} else if (students[i].gender == GENDER_FEMALE) {
stats.femaleCount++;
}
// 年龄统计
totalAge += students[i].age;
// 成绩统计
totalAverage += students[i].averageScore;
totalCourseCount += students[i].courseCount;
if (students[i].averageScore > stats.highestAverage) {
stats.highestAverage = students[i].averageScore;
}
if (students[i].averageScore < stats.lowestAverage) {
stats.lowestAverage = students[i].averageScore;
}
// 课程统计
for (int j = 0; j < students[i].courseCount; j++) {
bool exists = false;
for (int k = 0; k < uniqueCourseCount; k++) {
if (strcmp(courses[k], students[i].courses[j]) == 0) {
exists = true;
break;
}
}
if (!exists) {
strcpy(courses[uniqueCourseCount], students[i].courses[j]);
uniqueCourseCount++;
}
}
}
stats.averageAge = totalAge / studentCount;
stats.overallAverageScore = totalAverage / studentCount;
stats.totalCourses = uniqueCourseCount;
stats.averageCoursesPerStudent = (float)totalCourseCount / studentCount;
// 计算标准差
float variance = 0;
for (int i = 0; i < studentCount; i++) {
float diff = students[i].averageScore - stats.overallAverageScore;
variance += diff * diff;
}
variance /= studentCount;
stats.standardDeviation = sqrt(variance);
return stats;
}
/**
* @brief 查找最高分学生
*/
void findTopStudent() {
clearScreen();
printHeader("最高分学生");
if (studentCount == 0) {
printWarning("暂无学生数据!");
pauseSystem();
return;
}
int topIndex = 0;
for (int i = 1; i < studentCount; i++) {
if (students[i].averageScore > students[topIndex].averageScore) {
topIndex = i;
}
}
printf("\n最高平均分学生:\n");
displayStudentInfo(&students[topIndex]);
pauseSystem();
}
/**
* @brief 查找最低分学生
*/
void findBottomStudent() {
clearScreen();
printHeader("最低分学生");
if (studentCount == 0) {
printWarning("暂无学生数据!");
pauseSystem();
return;
}
int bottomIndex = 0;
for (int i = 1; i < studentCount; i++) {
if (students[i].averageScore < students[bottomIndex].averageScore) {
bottomIndex = i;
}
}
printf("\n最低平均分学生:\n");
displayStudentInfo(&students[bottomIndex]);
pauseSystem();
}
/**
* @brief 按课程查找最高分
*/
void findTopScoreInCourse() {
clearScreen();
printHeader("课程最高分查询");
if (studentCount == 0) {
printWarning("暂无学生数据!");
pauseSystem();
return;
}
char courseName[MAX_COURSE_NAME_LENGTH];
printf("\n");
safeInputString("请输入课程名称", courseName, MAX_COURSE_NAME_LENGTH);
float maxScore = -1;
int maxIndex = -1;
for (int i = 0; i < studentCount; i++) {
for (int j = 0; j < students[i].courseCount; j++) {
if (strcmp(students[i].courses[j], courseName) == 0) {
if (students[i].scores[j] > maxScore) {
maxScore = students[i].scores[j];
maxIndex = i;
}
}
}
}
if (maxIndex == -1) {
printError("未找到该课程!");
} else {
printf("\n课程 \"%s\" 最高分:\n", courseName);
printSeparator();
printf("学号: %s\n", students[maxIndex].studentID);
printf("姓名: %s\n", students[maxIndex].name);
printf("分数: %.2f\n", maxScore);
}
pauseSystem();
}
/**
* @brief 计算学生统计信息
*/
void calculateStudentStats(Student* student) {
if (student->courseCount == 0) {
student->totalScore = 0;
student->averageScore = 0;
return;
}
student->totalScore = 0;
for (int i = 0; i < student->courseCount; i++) {
student->totalScore += student->scores[i];
}
student->averageScore = student->totalScore / student->courseCount;
}
/**
* @brief 更新全局统计缓存
*/
void updateGlobalStats() {
if (studentCount == 0) {
overallAverageScore = 0;
highestScore = 0;
lowestScore = 0;
statsNeedUpdate = false;
return;
}
float total = 0;
highestScore = students[0].averageScore;
lowestScore = students[0].averageScore;
for (int i = 0; i < studentCount; i++) {
total += students[i].averageScore;
if (students[i].averageScore > highestScore) {
highestScore = students[i].averageScore;
}
if (students[i].averageScore < lowestScore) {
lowestScore = students[i].averageScore;
}
}
overallAverageScore = total / studentCount;
statsNeedUpdate = false;
}
+71
View File
@@ -0,0 +1,71 @@
/**
* @file statistical_analysis.h
* @brief 统计分析功能头文件
* @note 包含各种统计分析功能的函数声明
*/
#ifndef STATISTICAL_ANALYSIS_H
#define STATISTICAL_ANALYSIS_H
#include "config.h"
#include "main_menu.h"
// 课程统计结构体
typedef struct {
int studentCount;
float maxScore;
float minScore;
float totalScore;
float averageScore;
float passRate;
} CourseStats;
// 分数分布结构体
typedef struct {
int excellent; // 90-100分
int good; // 80-89分
int medium; // 70-79分
int pass; // 60-69分
int fail; // 0-59分
} ScoreDistribution;
// 学生排名结构体
typedef struct {
int studentIndex;
float averageScore;
float totalScore;
} StudentRank;
// 总体统计结构体
typedef struct {
int totalStudents;
int maleCount;
int femaleCount;
float averageAge;
float highestAverage;
float lowestAverage;
float overallAverageScore;
float standardDeviation;
int totalCourses;
float averageCoursesPerStudent;
} OverallStats;
// 主要统计分析函数
void displayCourseStatistics(); // 显示课程统计信息
void displayScoreDistribution(); // 显示分数分布
void displayStudentRanking(); // 显示学生排名
void displayOverallStatistics(); // 显示系统总体统计
// 查找功能
void findTopStudent(); // 查找最高分学生
void findBottomStudent(); // 查找最低分学生
void findTopScoreInCourse(); // 按课程查找最高分
// 计算函数
CourseStats calculateCourseStats(const char* courseName);
ScoreDistribution calculateScoreDistribution();
OverallStats calculateOverallStats();
void calculateStudentStats(Student* student);
void updateGlobalStats();
#endif // STATISTICAL_ANALYSIS_H
+18
View File
@@ -0,0 +1,18 @@
#ifndef STU_DATA_H
#define STU_DATA_H
#include "config.h"
// 学生数据管理相关函数 (CRUD)
void loadStudentsFromFile(); // 从文件加载学生数据
void saveStudentsToFile(); // 将学生数据保存到文件
void addStudent(); // 增加学生信息
void deleteStudent(); // 删除学生信息
void modifyStudent(); // 修改学生信息
void searchStudentByID(); // 按学号查找学生
void searchStudentByName(); // 按姓名查找学生
void displayAllStudents(); // 显示所有学生信息
void displayStudentInfo(const Student* student); // 显示单个学生信息
void sortStudents(int criteria, int order); // 统一排序函数,根据参数选择排序依据和升降序
#endif // STU_DATA_H
+614
View File
@@ -0,0 +1,614 @@
/**
* @file stu_data.c
* @brief 学生数据管理实现文件
* @note 实现学生信息的增删改查功能
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "stu.data.h"
#include "config.h"
#include "globals.h"
#include "auxiliary.h"
#include "statistical_analysis.h"
/**
* @brief 从CSV文件加载学生数据
*/
void loadStudentsFromFile() {
FILE* file = fopen(STUDENTS_FILE, "r");
if (file == NULL) {
studentCount = 0;
printInfo("学生数据文件不存在,将创建新文件。");
return;
}
char line[1024];
studentCount = 0;
// 跳过CSV头部
if (fgets(line, sizeof(line), file) == NULL) {
fclose(file);
studentCount = 0;
return;
}
// 读取学生数据
while (fgets(line, sizeof(line), file) != NULL && studentCount < MAX_STUDENTS) {
Student* student = &students[studentCount];
memset(student, 0, sizeof(Student));
// 解析CSV行
char* token = strtok(line, ",");
if (token == NULL) continue;
// 学号
strncpy(student->studentID, token, MAX_ID_LENGTH - 1);
// 姓名
token = strtok(NULL, ",");
if (token == NULL) continue;
strncpy(student->name, token, MAX_NAME_LENGTH - 1);
// 年龄
token = strtok(NULL, ",");
if (token == NULL) continue;
student->age = atoi(token);
// 性别
token = strtok(NULL, ",");
if (token == NULL) continue;
student->gender = token[0];
// 课程数量
token = strtok(NULL, ",");
if (token == NULL) continue;
student->courseCount = atoi(token);
// 课程和成绩
for (int i = 0; i < student->courseCount && i < MAX_COURSES; i++) {
// 课程名称
token = strtok(NULL, ",");
if (token == NULL) break;
strncpy(student->courses[i], token, MAX_COURSE_NAME_LENGTH - 1);
// 成绩
token = strtok(NULL, ",");
if (token == NULL) break;
student->scores[i] = atof(token);
}
// 总分
token = strtok(NULL, ",");
if (token != NULL) {
student->totalScore = atof(token);
}
// 平均分
token = strtok(NULL, ",");
if (token != NULL) {
student->averageScore = atof(token);
}
studentCount++;
}
fclose(file);
// 更新统计信息
statsNeedUpdate = true;
}
/**
* @brief 将学生数据保存到CSV文件
*/
void saveStudentsToFile() {
FILE* file = fopen(STUDENTS_FILE, "w");
if (file == NULL) {
printError("无法保存学生数据!");
return;
}
// 写入CSV头部
fprintf(file, "学号,姓名,年龄,性别,课程数量");
for (int i = 0; i < MAX_COURSES; i++) {
fprintf(file, ",课程%d,成绩%d", i+1, i+1);
}
fprintf(file, ",总分,平均分\n");
// 写入学生数据
for (int i = 0; i < studentCount; i++) {
Student* student = &students[i];
// 基本信息
fprintf(file, "%s,%s,%d,%c,%d",
student->studentID,
student->name,
student->age,
student->gender,
student->courseCount);
// 课程和成绩
for (int j = 0; j < MAX_COURSES; j++) {
if (j < student->courseCount) {
fprintf(file, ",%s,%.2f", student->courses[j], student->scores[j]);
} else {
fprintf(file, ",,"); // 空的课程和成绩
}
}
// 总分和平均分
fprintf(file, ",%.2f,%.2f\n", student->totalScore, student->averageScore);
}
fclose(file);
dataModified = false;
printSuccess("学生数据已保存到CSV文件!");
}
/**
* @brief 添加学生信息
*/
void addStudent() {
clearScreen();
printHeader("添加学生信息");
if (studentCount >= MAX_STUDENTS) {
printError("学生数量已达上限!");
pauseSystem();
return;
}
Student newStudent;
memset(&newStudent, 0, sizeof(Student));
printf("\n");
// 输入学号
while (1) {
safeInputString("请输入学号", newStudent.studentID, MAX_ID_LENGTH);
if (!isValidStudentID(newStudent.studentID)) {
printError("学号格式无效!");
continue;
}
// 检查学号是否已存在
bool exists = false;
for (int i = 0; i < studentCount; i++) {
if (strcmp(students[i].studentID, newStudent.studentID) == 0) {
printError("学号已存在!");
exists = true;
break;
}
}
if (!exists) break;
}
// 输入姓名
while (1) {
safeInputString("请输入姓名", newStudent.name, MAX_NAME_LENGTH);
if (isValidName(newStudent.name)) break;
printError("姓名格式无效!");
}
// 输入年龄
newStudent.age = safeInputInt("请输入年龄", 10, 100);
// 输入性别
while (1) {
printf("请输入性别 (M/F): ");
char gender;
scanf(" %c", &gender);
clearInputBuffer();
if (isValidGender(gender)) {
newStudent.gender = gender;
break;
}
printError("性别输入无效!请输入 M 或 F");
}
// 输入课程信息
printf("\n开始输入课程信息:\n");
newStudent.courseCount = 0;
while (newStudent.courseCount < MAX_COURSES) {
printf("\n第 %d 门课程:\n", newStudent.courseCount + 1);
safeInputString("课程名称",
newStudent.courses[newStudent.courseCount],
MAX_COURSE_NAME_LENGTH);
newStudent.scores[newStudent.courseCount] =
safeInputFloat("课程分数", MIN_SCORE, MAX_SCORE);
newStudent.courseCount++;
if (newStudent.courseCount < MAX_COURSES) {
printf("\n是否继续添加课程?(y/n): ");
char choice;
scanf(" %c", &choice);
clearInputBuffer();
if (choice != 'y' && choice != 'Y') {
break;
}
}
}
// 计算总分和平均分
calculateStudentStats(&newStudent);
// 添加到数组
students[studentCount] = newStudent;
studentCount++;
// 标记数据已修改
dataModified = true;
statsNeedUpdate = true;
printSuccess("学生信息添加成功!");
printf("学号: %s\n", newStudent.studentID);
printf("姓名: %s\n", newStudent.name);
printf("总分: %.2f\n", newStudent.totalScore);
printf("平均分: %.2f\n", newStudent.averageScore);
pauseSystem();
}
/**
* @brief 删除学生信息
*/
void deleteStudent() {
clearScreen();
printHeader("删除学生信息");
if (studentCount == 0) {
printWarning("暂无学生数据!");
pauseSystem();
return;
}
char studentID[MAX_ID_LENGTH];
printf("\n");
safeInputString("请输入要删除的学生学号", studentID, MAX_ID_LENGTH);
// 查找学生
for (int i = 0; i < studentCount; i++) {
if (strcmp(students[i].studentID, studentID) == 0) {
printf("\n找到学生信息:\n");
printf("学号: %s\n", students[i].studentID);
printf("姓名: %s\n", students[i].name);
printf("\n确认删除?(y/n): ");
char choice;
scanf(" %c", &choice);
clearInputBuffer();
if (choice == 'y' || choice == 'Y') {
// 移动后面的学生向前
for (int j = i; j < studentCount - 1; j++) {
students[j] = students[j + 1];
}
studentCount--;
dataModified = true;
statsNeedUpdate = true;
printSuccess("学生信息删除成功!");
} else {
printInfo("删除操作已取消。");
}
pauseSystem();
return;
}
}
printError("未找到该学号的学生!");
pauseSystem();
}
/**
* @brief 修改学生信息
*/
void modifyStudent() {
clearScreen();
printHeader("修改学生信息");
if (studentCount == 0) {
printWarning("暂无学生数据!");
pauseSystem();
return;
}
char studentID[MAX_ID_LENGTH];
printf("\n");
safeInputString("请输入要修改的学生学号", studentID, MAX_ID_LENGTH);
// 查找学生
for (int i = 0; i < studentCount; i++) {
if (strcmp(students[i].studentID, studentID) == 0) {
printf("\n找到学生信息:\n");
printf("学号: %s\n", students[i].studentID);
printf("姓名: %s\n", students[i].name);
printf("年龄: %d\n", students[i].age);
printf("性别: %c\n", students[i].gender);
printf("\n修改选项:\n");
printf("1. 修改姓名\n");
printf("2. 修改年龄\n");
printf("3. 修改性别\n");
printf("4. 修改课程成绩\n");
printf("0. 返回\n");
int choice = safeInputInt("请选择修改项", 0, 4);
switch (choice) {
case 1: // 修改姓名
safeInputString("请输入新姓名", students[i].name, MAX_NAME_LENGTH);
break;
case 2:
students[i].age = safeInputInt("请输入新年龄", 10, 100);
break;
case 3:
while (1) {
printf("请输入新性别 (M/F): ");
char gender;
scanf(" %c", &gender);
clearInputBuffer();
if (isValidGender(gender)) {
students[i].gender = gender;
break;
}
printError("性别输入无效!");
}
break;
case 4:
printf("\n当前课程列表:\n");
for (int j = 0; j < students[i].courseCount; j++) {
printf("%d. %s: %.2f\n", j + 1, students[i].courses[j], students[i].scores[j]);
}
printf("\n修改选项:\n");
printf("1. 修改现有课程成绩\n");
printf("2. 添加新课程\n");
printf("3. 删除课程\n");
printf("0. 返回\n");
int courseChoice = safeInputInt("请选择操作", 0, 3);
switch (courseChoice) {
case 1: // 修改现有课程成绩
if (students[i].courseCount == 0) {
printWarning("该学生没有课程记录!");
break;
}
int courseIndex = safeInputInt("请选择要修改的课程", 1, students[i].courseCount) - 1;
students[i].scores[courseIndex] = safeInputFloat("新成绩", MIN_SCORE, MAX_SCORE);
break;
case 2: // 添加新课程
if (students[i].courseCount >= MAX_COURSES) {
printWarning("课程数量已达上限!");
break;
}
safeInputString("课程名称", students[i].courses[students[i].courseCount], MAX_COURSE_NAME_LENGTH);
students[i].scores[students[i].courseCount] = safeInputFloat("课程成绩", MIN_SCORE, MAX_SCORE);
students[i].courseCount++;
break;
case 3: // 删除课程
if (students[i].courseCount == 0) {
printWarning("该学生没有课程记录!");
break;
}
courseIndex = safeInputInt("请选择要删除的课程", 1, students[i].courseCount) - 1;
// 移动数组元素
for (int k = courseIndex; k < students[i].courseCount - 1; k++) {
strcpy(students[i].courses[k], students[i].courses[k + 1]);
students[i].scores[k] = students[i].scores[k + 1];
}
students[i].courseCount--;
break;
}
break;
case 0:
return;
}
if (choice == 4) {
calculateStudentStats(&students[i]);
}
dataModified = true;
statsNeedUpdate = true;
printSuccess("学生信息修改成功!");
pauseSystem();
return;
}
}
printError("未找到该学号的学生!");
pauseSystem();
}
/**
* @brief 修改学生课程成绩
*/
/**
* @brief 按学号查找学生
*/
void searchStudentByID() {
clearScreen();
printHeader("按学号查找学生");
if (studentCount == 0) {
printWarning("暂无学生数据!");
pauseSystem();
return;
}
char studentID[MAX_ID_LENGTH];
printf("\n");
safeInputString("请输入学号", studentID, MAX_ID_LENGTH);
for (int i = 0; i < studentCount; i++) {
if (strcmp(students[i].studentID, studentID) == 0) {
displayStudentInfo(&students[i]);
pauseSystem();
return;
}
}
printError("未找到该学号的学生!");
pauseSystem();
}
/**
* @brief 按姓名查找学生
*/
void searchStudentByName() {
clearScreen();
printHeader("按姓名查找学生");
if (studentCount == 0) {
printWarning("暂无学生数据!");
pauseSystem();
return;
}
char name[MAX_NAME_LENGTH];
printf("\n");
safeInputString("请输入姓名(支持模糊查找)", name, MAX_NAME_LENGTH);
bool found = false;
for (int i = 0; i < studentCount; i++) {
if (strstr(students[i].name, name) != NULL) {
if (!found) {
printf("\n找到以下匹配的学生:\n");
printSeparator();
found = true;
}
displayStudentInfo(&students[i]);
printf("\n");
}
}
if (!found) {
printError("未找到匹配的学生!");
}
pauseSystem();
}
/**
* @brief 显示所有学生信息
*/
void displayAllStudents() {
clearScreen();
printHeader("所有学生信息");
if (studentCount == 0) {
printWarning("暂无学生数据!");
pauseSystem();
return;
}
printf("\n");
// 调整中文表头的对齐格式,考虑中文字符的显示宽度
printf("%-10s %-12s %-6s %-6s %-8s %-8s\n",
"学号", "姓名", "年龄", "性别", "总分", "平均分");
printf("========================================\n");
for (int i = 0; i < studentCount; i++) {
printf("%-10s %-12s %-6d %-6c %-8.2f %-8.2f\n",
students[i].studentID,
students[i].name,
students[i].age,
students[i].gender,
students[i].totalScore,
students[i].averageScore);
}
printf("\n总学生数: %d\n", studentCount);
pauseSystem();
}
/**
* @brief 显示单个学生详细信息
*/
void displayStudentInfo(const Student* student) {
printf("\n学生详细信息:\n");
printSeparator();
printf("学号: %s\n", student->studentID);
printf("姓名: %s\n", student->name);
printf("年龄: %d\n", student->age);
printf("性别: %c\n", student->gender);
printf("课程数量: %d\n", student->courseCount);
if (student->courseCount > 0) {
printf("\n课程成绩:\n");
for (int i = 0; i < student->courseCount; i++) {
printf(" %s: %.2f分\n",
student->courses[i],
student->scores[i]);
}
printf("\n总分: %.2f\n", student->totalScore);
printf("平均分: %.2f\n", student->averageScore);
}
}
/**
* @brief 排序学生信息
*/
void sortStudents(int criteria, int order) {
if (studentCount <= 1) return;
// 使用冒泡排序
for (int i = 0; i < studentCount - 1; i++) {
for (int j = 0; j < studentCount - 1 - i; j++) {
bool shouldSwap = false;
switch (criteria) {
case SORT_BY_ID:
shouldSwap = (order == SORT_ASCENDING) ?
strcmp(students[j].studentID, students[j + 1].studentID) > 0 :
strcmp(students[j].studentID, students[j + 1].studentID) < 0;
break;
case SORT_BY_NAME:
shouldSwap = (order == SORT_ASCENDING) ?
strcmp(students[j].name, students[j + 1].name) > 0 :
strcmp(students[j].name, students[j + 1].name) < 0;
break;
case SORT_BY_TOTAL_SCORE:
shouldSwap = (order == SORT_ASCENDING) ?
students[j].totalScore > students[j + 1].totalScore :
students[j].totalScore < students[j + 1].totalScore;
break;
case SORT_BY_AVERAGE_SCORE:
shouldSwap = (order == SORT_ASCENDING) ?
students[j].averageScore > students[j + 1].averageScore :
students[j].averageScore < students[j + 1].averageScore;
break;
}
if (shouldSwap) {
Student temp = students[j];
students[j] = students[j + 1];
students[j + 1] = temp;
}
}
}
dataModified = true;
}
Binary file not shown.
Binary file not shown.
+6
View File
@@ -0,0 +1,6 @@
admin
123456
2
3
0
0
+265
View File
@@ -0,0 +1,265 @@
/**
* @file user_manage.c
* @brief 用户管理实现文件
* @note 实现用户认证和管理功能
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "user_manage.h"
#include "config.h"
#include "globals.h"
#include "auxiliary.h"
/**
* @brief 处理用户登录
* @return 登录成功返回1,失败返回0
*/
int loginSystem() {
char username[MAX_USERNAME_LENGTH];
char password[MAX_PASSWORD_LENGTH];
printf("\n");
safeInputString("请输入用户名", username, MAX_USERNAME_LENGTH);
safeInputString("请输入密码", password, MAX_PASSWORD_LENGTH);
// 验证用户名和密码
for (int i = 0; i < userCount; i++) {
if (strcmp(users[i].username, username) == 0 &&
strcmp(users[i].password, password) == 0) {
// 登录成功
strcpy(currentUser, username);
isCurrentUserAdmin = users[i].isAdmin;
return 1;
}
}
return 0; // 登录失败
}
/**
* @brief 从文件加载用户数据
*/
void loadUsersFromFile() {
FILE* file = fopen(USERS_FILE, "r");
if (file == NULL) {
// 文件不存在,创建默认管理员账户
strcpy(users[0].username, "admin");
strcpy(users[0].password, "123456");
users[0].isAdmin = true;
strcpy(users[1].username, "teacher");
strcpy(users[1].password, "password");
users[1].isAdmin = false;
userCount = 2;
// 保存默认用户到文件
saveUsersToFile();
printInfo("已创建默认用户账户:");
printInfo("管理员 - 用户名: admin, 密码: 123456");
printInfo("普通用户 - 用户名: teacher, 密码: password");
return;
}
userCount = 0;
char line[200];
while (fgets(line, sizeof(line), file) && userCount < MAX_USERS) {
// 移除换行符
line[strcspn(line, "\n")] = '\0';
// 解析格式:username:password:isAdmin
char* username = strtok(line, ":");
char* password = strtok(NULL, ":");
char* adminFlag = strtok(NULL, ":");
if (username && password && adminFlag) {
strcpy(users[userCount].username, username);
strcpy(users[userCount].password, password);
users[userCount].isAdmin = (strcmp(adminFlag, "1") == 0);
userCount++;
}
}
fclose(file);
}
/**
* @brief 将用户数据保存到文件
*/
void saveUsersToFile() {
FILE* file = fopen(USERS_FILE, "w");
if (file == NULL) {
printError("无法保存用户数据!");
return;
}
for (int i = 0; i < userCount; i++) {
fprintf(file, "%s:%s:%d\n",
users[i].username,
users[i].password,
users[i].isAdmin ? 1 : 0);
}
fclose(file);
}
/**
* @brief 增加用户账户
*/
void addUserAccount() {
clearScreen();
printHeader("添加用户账户");
if (userCount >= MAX_USERS) {
printError("用户数量已达上限!");
pauseSystem();
return;
}
char username[MAX_USERNAME_LENGTH];
char password[MAX_PASSWORD_LENGTH];
printf("\n");
safeInputString("请输入新用户名", username, MAX_USERNAME_LENGTH);
// 检查用户名是否已存在
for (int i = 0; i < userCount; i++) {
if (strcmp(users[i].username, username) == 0) {
printError("用户名已存在!");
pauseSystem();
return;
}
}
safeInputString("请输入密码", password, MAX_PASSWORD_LENGTH);
printf("\n用户类型:\n");
printf("1. 普通用户\n");
printf("2. 管理员\n");
int userType = safeInputInt("请选择用户类型", 1, 2);
// 添加新用户
strcpy(users[userCount].username, username);
strcpy(users[userCount].password, password);
users[userCount].isAdmin = (userType == 2);
userCount++;
// 保存到文件
saveUsersToFile();
dataModified = true;
printSuccess("用户添加成功!");
pauseSystem();
}
/**
* @brief 删除用户账户
*/
void deleteUserAccount() {
clearScreen();
printHeader("删除用户账户");
if (userCount <= 1) {
printError("至少需要保留一个用户账户!");
pauseSystem();
return;
}
char username[MAX_USERNAME_LENGTH];
printf("\n");
safeInputString("请输入要删除的用户名", username, MAX_USERNAME_LENGTH);
// 不能删除当前登录用户
if (strcmp(username, currentUser) == 0) {
printError("不能删除当前登录的用户!");
pauseSystem();
return;
}
// 查找并删除用户
for (int i = 0; i < userCount; i++) {
if (strcmp(users[i].username, username) == 0) {
// 移动后面的用户向前
for (int j = i; j < userCount - 1; j++) {
users[j] = users[j + 1];
}
userCount--;
// 保存到文件
saveUsersToFile();
dataModified = true;
printSuccess("用户删除成功!");
pauseSystem();
return;
}
}
printError("用户不存在!");
pauseSystem();
}
/**
* @brief 修改用户密码
*/
void modifyUserPassword() {
clearScreen();
printHeader("修改用户密码");
char username[MAX_USERNAME_LENGTH];
char newPassword[MAX_PASSWORD_LENGTH];
printf("\n");
safeInputString("请输入用户名", username, MAX_USERNAME_LENGTH);
// 查找用户
for (int i = 0; i < userCount; i++) {
if (strcmp(users[i].username, username) == 0) {
safeInputString("请输入新密码", newPassword, MAX_PASSWORD_LENGTH);
strcpy(users[i].password, newPassword);
// 保存到文件
saveUsersToFile();
dataModified = true;
printSuccess("密码修改成功!");
pauseSystem();
return;
}
}
printError("用户不存在!");
pauseSystem();
}
/**
* @brief 查看所有用户
*/
void viewAllUsers() {
clearScreen();
printHeader("所有用户列表");
if (userCount == 0) {
printWarning("暂无用户数据!");
pauseSystem();
return;
}
printf("\n");
printf("%-20s %-15s %-10s\n", "用户名", "用户类型", "状态");
printSeparator();
for (int i = 0; i < userCount; i++) {
printf("%-20s %-15s %-10s\n",
users[i].username,
users[i].isAdmin ? "管理员" : "普通用户",
strcmp(users[i].username, currentUser) == 0 ? "当前用户" : "");
}
printf("\n总用户数: %d\n", userCount);
pauseSystem();
}
+13
View File
@@ -0,0 +1,13 @@
#ifndef USER_MANAGE_H
#define USER_MANAGE_H
// 用户认证与管理相关函数
int loginSystem(); // 处理用户登录
void loadUsersFromFile(); // 从文件加载用户数据
void saveUsersToFile(); // 将用户数据保存到文件
void addUserAccount(); // 增加用户
void deleteUserAccount(); // 删除用户
void modifyUserPassword(); // 修改用户密码
void viewAllUsers(); // 查看所有用户
#endif // USER_MANAGE_H