C语言课程设计,课程管理系统如何实现核心功能?

99ANYc3cd6
预计阅读时长 51 分钟
位置: 首页 C语言 正文

C语言课程设计:课程管理系统

项目概述与需求分析

1 项目背景 在高校教学管理中,课程信息的管理是一项基础且重要的工作,为了简化教务人员的工作,提高管理效率,开发一个基于C语言的命令行课程管理系统,用于实现对课程信息的增、删、改、查等基本操作,具有很高的实用价值。

c语言课程设计课程管理系统
(图片来源网络,侵删)

2 系统目标

  1. 信息录入:能够将新课程的信息(如课程编号、课程名称、授课教师、学分、上课时间等)添加到系统中。
  2. 信息查询:能够按照不同的条件(如课程编号、课程名称)查询课程信息,并显示查询结果。
  3. 信息修改:能够根据课程编号,查找到对应课程并修改其信息(除课程编号外)。
  4. 信息删除:能够根据课程编号,从系统中删除指定的课程。
  5. 数据持久化:系统能够将课程信息保存在文件中,以便在程序关闭后再次启动时可以加载之前的数据。
  6. 界面友好:提供清晰、简洁的菜单驱动界面,方便用户操作。

3 功能模块划分 根据需求分析,系统可以划分为以下几个核心模块:

  • 主菜单模块:提供所有功能的入口。
  • 课程添加模块:实现“增加”功能。
  • 课程查询模块:实现“查询”功能,可细分为按ID查询和按名称查询。
  • 课程修改模块:实现“修改”功能。
  • 课程删除模块:实现“删除”功能。
  • 数据存储与加载模块:实现从文件读取数据和向文件写入数据。
  • 显示所有课程模块:以表格形式列出系统中所有课程信息。

系统设计

1 数据结构设计 为了存储课程信息,我们定义一个结构体 Course,为了管理所有课程,使用一个结构体数组 courses,并通过一个整型变量 count 来记录当前系统中课程的总数。

// 课程信息结构体
typedef struct {
    char id[20];        // 课程编号 (唯一标识)
    char name[50];      // 课程名称
    char teacher[30];   // 授课教师
    int credit;         // 学分
    char time[30];      // 上课时间 ( 周一 8:00-10:00)
} Course;
// 课程管理系统结构体
typedef struct {
    Course courses[100]; // 假设最多存储100门课程
    int count;           // 当前课程数量
} CourseSystem;

2 功能函数设计 | 函数名 | 功能描述 | 参数 | 返回值 | | :--- | :--- | :--- | :--- | | main | 程序入口,显示主菜单,调用其他功能函数 | 无 | 无 | | initSystem | 初始化系统,尝试从文件加载数据 | CourseSystem *sys | 无 | | saveToFile | 将当前系统中的所有课程信息保存到文件 | CourseSystem *sys | 无 | | showMenu | 显示系统主菜单 | 无 | 无 | | addCourse | 添加一门新课程 | CourseSystem *sys | 无 | | findCourseById | 按课程编号查询课程 | CourseSystem *sys, char *id | 查找到的课程在数组中的索引,未找到返回-1 | | findCourseByName | 按课程名称查询课程 | CourseSystem *sys, char *name | 查找到的课程在数组中的索引,未找到返回-1 | | queryCourse | 提供查询子菜单,调用具体查询函数 | CourseSystem *sys | 无 | | modifyCourse | 修改指定课程的信息 | CourseSystem *sys | 无 | | deleteCourse | 删除指定编号的课程 | CourseSystem *sys | 无 | | displayAllCourses | 以表格形式显示所有课程信息 | CourseSystem *sys | 无 | | pauseAndClear | 暂停屏幕并清屏,提升用户体验 | 无 | 无 |

3 文件设计 使用一个文本文件 courses.dat 来持久化存储数据。

  • 文件格式:每行存储一门课程的信息,字段之间用逗号()或制表符(\t)分隔。
  • CS101,程序设计基础,张三,4,周一 8:00-10:00
    MATH201,高等数学,李四,5,周二 10:00-12:00
    ENG102,大学英语,王五,3,周三 14:00-16:00

核心代码实现

下面是各个功能模块的C语言代码实现。

1 头文件 (course_system.h)

#ifndef COURSE_SYSTEM_H
#define COURSE_SYSTEM_H
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <conio.h> // 用于 getch(),Windows下有效,Linux/Mac可用其他方式替代
// 课程信息结构体
typedef struct {
    char id[20];
    char name[50];
    char teacher[30];
    int credit;
    char time[30];
} Course;
// 课程管理系统结构体
typedef struct {
    Course courses[100];
    int count;
} CourseSystem;
// 函数声明
void initSystem(CourseSystem *sys);
void saveToFile(CourseSystem *sys);
void showMenu();
void addCourse(CourseSystem *sys);
void queryCourse(CourseSystem *sys);
void modifyCourse(CourseSystem *sys);
void deleteCourse(CourseSystem *sys);
void displayAllCourses(CourseSystem *sys);
int findCourseById(CourseSystem *sys, char *id);
int findCourseByName(CourseSystem *sys, char *name);
void pauseAndClear();
#endif

2 主函数与菜单 (main.c)

#include "course_system.h"
int main() {
    CourseSystem sys;
    initSystem(&sys); // 初始化系统,加载数据
    int choice;
    do {
        showMenu();
        printf("请输入您的选择 (0-6): ");
        scanf("%d", &choice);
        // 清除输入缓冲区中的回车符
        while (getchar() != '\n');
        switch (choice) {
            case 1:
                addCourse(&sys);
                break;
            case 2:
                queryCourse(&sys);
                break;
            case 3:
                modifyCourse(&sys);
                break;
            case 4:
                deleteCourse(&sys);
                break;
            case 5:
                displayAllCourses(&sys);
                break;
            case 6:
                printf("正在保存数据并退出系统...\n");
                saveToFile(&sys);
                pauseAndClear();
                printf("感谢使用,再见!\n");
                break;
            case 0:
                printf("确认要退出吗?(y/n): ");
                char confirm = getchar();
                if (confirm == 'y' || confirm == 'Y') {
                    printf("正在保存数据并退出系统...\n");
                    saveToFile(&sys);
                    pauseAndClear();
                    printf("感谢使用,再见!\n");
                    return 0;
                }
                break;
            default:
                printf("无效的输入,请重新选择!\n");
                break;
        }
        pauseAndClear(); // 每次操作后暂停并清屏
    } while (choice != 0 && choice != 6);
    return 0;
}

3 功能函数实现 (functions.c)

#include "course_system.h"
// 初始化系统,从文件加载数据
void initSystem(CourseSystem *sys) {
    sys->count = 0;
    FILE *fp = fopen("courses.dat", "r");
    if (fp == NULL) {
        printf("数据文件不存在或无法打开,将创建新文件,\n");
        return;
    }
    while (fscanf(fp, "%19[^,],%49[^,],%29[^,],%d,%29[^\n]",
                  sys->courses[sys->count].id,
                  sys->courses[sys->count].name,
                  sys->courses[sys->count].teacher,
                  &sys->courses[sys->count].credit,
                  sys->courses[sys->count].time) == 5) {
        sys->count++;
        if (sys->count >= 100) break; // 防止数组越界
    }
    fclose(fp);
    printf("成功加载 %d 门课程信息,\n", sys->count);
}
// 保存数据到文件
void saveToFile(CourseSystem *sys) {
    FILE *fp = fopen("courses.dat", "w");
    if (fp == NULL) {
        printf("无法打开文件进行保存!\n");
        return;
    }
    for (int i = 0; i < sys->count; i++) {
        fprintf(fp, "%s,%s,%s,%d,%s\n",
                sys->courses[i].id,
                sys->courses[i].name,
                sys->courses[i].teacher,
                sys->courses[i].credit,
                sys->courses[i].time);
    }
    fclose(fp);
}
// 显示主菜单
void showMenu() {
    printf("========================================\n");
    printf("=        欢迎使用课程管理系统          =\n");
    printf("========================================\n");
    printf("=  1. 添加课程                         =\n");
    printf("=  2. 查询课程                         =\n");
    printf("=  3. 修改课程                         =\n");
    printf("=  4. 删除课程                         =\n");
    printf("=  5. 显示所有课程                     =\n");
    printf("=  6. 保存并退出                       =\n");
    printf("=  0. 退出(不保存)                   =\n");
    printf("========================================\n");
}
// 添加课程
void addCourse(CourseSystem *sys) {
    if (sys->count >= 100) {
        printf("课程数量已达上限,无法添加!\n");
        return;
    }
    Course c;
    printf("请输入课程编号: ");
    scanf("%s", c.id);
    // 检查ID是否已存在
    if (findCourseById(sys, c.id) != -1) {
        printf("错误:该课程编号已存在!\n");
        return;
    }
    printf("请输入课程名称: ");
    scanf("%s", c.name);
    printf("请输入授课教师: ");
    scanf("%s", c.teacher);
    printf("请输入学分: ");
    scanf("%d", &c.credit);
    printf("请输入上课时间: ");
    scanf("%s", c.time);
    sys->courses[sys->count++] = c;
    printf("课程添加成功!\n");
}
// 查询课程
void queryCourse(CourseSystem *sys) {
    int subChoice;
    printf("--- 查询方式 ---\n");
    printf("1. 按课程编号查询\n");
    printf("2. 按课程名称查询\n");
    printf("请选择查询方式: ");
    scanf("%d", &subChoice);
    while (getchar() != '\n'); // 清空缓冲区
    char keyword[50];
    int index = -1;
    switch (subChoice) {
        case 1:
            printf("请输入要查询的课程编号: ");
            scanf("%s", keyword);
            index = findCourseById(sys, keyword);
            break;
        case 2:
            printf("请输入要查询的课程名称: ");
            scanf("%s", keyword);
            index = findCourseByName(sys, keyword);
            break;
        default:
            printf("无效的选择!\n");
            return;
    }
    if (index != -1) {
        printf("\n--- 查询结果 ---\n");
        printf("课程编号: %s\n", sys->courses[index].id);
        printf("课程名称: %s\n", sys->courses[index].name);
        printf("授课教师: %s\n", sys->courses[index].teacher);
        printf("学    分: %d\n", sys->courses[index].credit);
        printf("上课时间: %s\n", sys->courses[index].time);
    } else {
        printf("未找到相关课程!\n");
    }
}
// 修改课程
void modifyCourse(CourseSystem *sys) {
    char id[20];
    printf("请输入要修改的课程编号: ");
    scanf("%s", id);
    int index = findCourseById(sys, id);
    if (index == -1) {
        printf("未找到该课程!\n");
        return;
    }
    printf("找到课程:%s\n", sys->courses[index].name);
    printf("请输入新的课程名称 (原: %s): ", sys->courses[index].name);
    scanf("%s", sys->courses[index].name);
    printf("请输入新的授课教师 (原: %s): ", sys->courses[index].teacher);
    scanf("%s", sys->courses[index].teacher);
    printf("请输入新的学分 (原: %d): ", sys->courses[index].credit);
    scanf("%d", &sys->courses[index].credit);
    printf("请输入新的上课时间 (原: %s): ", sys->courses[index].time);
    scanf("%s", sys->courses[index].time);
    printf("课程信息修改成功!\n");
}
// 删除课程
void deleteCourse(CourseSystem *sys) {
    char id[20];
    printf("请输入要删除的课程编号: ");
    scanf("%s", id);
    int index = findCourseById(sys, id);
    if (index == -1) {
        printf("未找到该课程!\n");
        return;
    }
    printf("确认要删除课程 \"%s\" 吗?(y/n): ", sys->courses[index].name);
    char confirm = getchar();
    if (confirm == 'y' || confirm == 'Y') {
        // 将后面的元素前移,覆盖要删除的元素
        for (int i = index; i < sys->count - 1; i++) {
            sys->courses[i] = sys->courses[i + 1];
        }
        sys->count--;
        printf("课程删除成功!\n");
    } else {
        printf("删除操作已取消,\n");
    }
}
// 显示所有课程
void displayAllCourses(CourseSystem *sys) {
    if (sys->count == 0) {
        printf("当前没有任何课程信息!\n");
        return;
    }
    printf("\n--- 所有课程信息 ---\n");
    printf("-----------------------------------------------------------------\n");
    printf("| %-10s | %-20s | %-10s | %-5s | %-15s |\n", "课程编号", "课程名称", "授课教师", "学分", "上课时间");
    printf("-----------------------------------------------------------------\n");
    for (int i = 0; i < sys->count; i++) {
        printf("| %-10s | %-20s | %-10s | %-5d | %-15s |\n",
               sys->courses[i].id,
               sys->courses[i].name,
               sys->courses[i].teacher,
               sys->courses[i].credit,
               sys->courses[i].time);
    }
    printf("-----------------------------------------------------------------\n");
    printf("总计: %d 门课程\n\n", sys->count);
}
// 按ID查找,返回索引,找不到返回-1
int findCourseById(CourseSystem *sys, char *id) {
    for (int i = 0; i < sys->count; i++) {
        if (strcmp(sys->courses[i].id, id) == 0) {
            return i;
        }
    }
    return -1;
}
// 按名称查找,返回第一个匹配的索引,找不到返回-1
int findCourseByName(CourseSystem *sys, char *name) {
    for (int i = 0; i < sys->count; i++) {
        if (strstr(sys->courses[i].name, name) != NULL) { // 使用strstr实现模糊查询
            return i;
        }
    }
    return -1;
}
// 暂停并清屏
void pauseAndClear() {
    printf("\n按任意键继续...");
    getch(); // 等待用户按键
    #ifdef _WIN32
        system("cls"); // Windows清屏
    #else
        system("clear"); // Linux/Mac清屏
    #endif
}

编译与运行

  1. 保存文件:将上述代码分别保存为 course_system.hmain.cfunctions.c
  2. 编译:打开命令行(如Windows的CMD或Linux的Terminal),使用GCC进行编译。
    gcc main.c functions.c -o course_system.exe
    • 在Linux/macOS上,编译命令为:
      gcc main.c functions.c -o course_system
  3. 运行
    • 在Windows上:
      course_system.exe
    • 在Linux/macOS上:
      ./course_system

首次运行:程序会提示“数据文件不存在...”,然后创建一个空的 courses.dat 文件,之后就可以开始添加课程了。


测试方案

  1. 添加功能测试

    • 输入1,添加多门课程,确保信息正确录入。
    • 尝试添加一个已存在的课程ID,系统应提示错误。
    • 添加超过100门课程,系统应提示已达上限。
  2. 查询功能测试

    • 输入2,选择1(按ID查询),查询一个存在的ID,确认显示正确。
    • 查询一个不存在的ID,系统应提示“未找到”。
    • 输入2,选择2(按名称查询),查询一个存在的名称,确认显示正确。
    • 查询一个不存在的名称,系统应提示“未找到”。
  3. 修改功能测试

    • 输入3,输入一个存在的课程ID,修改其信息,然后通过查询功能验证修改是否成功。
    • 输入3,输入一个不存在的课程ID,系统应提示“未找到”。
  4. 删除功能测试

    • 输入4,输入一个存在的课程ID,确认删除,通过“显示所有课程”功能验证该课程已被删除。
    • 输入4,输入一个不存在的课程ID,系统应提示“未找到”。
    • 删除后,再次启动程序,确认该课程未被重新加载。
  5. 数据持久化测试

    • 添加、修改、删除一些课程后,选择“6. 保存并退出”。
    • 关闭程序,重新启动,选择“5. 显示所有课程”,检查数据是否与退出前一致。
  6. 边界与异常测试

    • 在主菜单输入0,确认是否安全退出。
    • 在主菜单输入一个无效的数字(如7),系统是否给出错误提示。
    • 输入信息时,尝试输入超长的字符串,观察系统行为(当前代码没有做长度限制,实际项目中应增加)。

总结与展望

1 总结 本课程设计实现了一个功能完备、结构清晰的课程管理系统,它成功运用了C语言的核心知识点,包括结构体、数组、文件I/O、函数模块化设计等,系统通过菜单驱动,操作直观,并具备数据持久化能力,达到了预期的设计目标。

2 不足与改进方向

  1. 数据安全性:当前系统没有密码保护,任何用户都可以修改数据,可以增加用户登录模块,区分管理员和学生等不同角色。
  2. 输入验证:对用户输入(如学分必须是正整数)的校验不够严格,可以增加输入验证函数,确保数据的合法性。
  3. 数据结构优化:使用固定大小的数组存储课程,不够灵活,可以改用动态内存分配(如mallocrealloc)或链表来管理课程,实现动态扩容。
  4. 用户体验pauseAndClear函数使用了平台相关的命令(cls/clear),可以封装一个更通用的清屏函数,菜单和提示信息可以做得更美观。
  5. 功能扩展
    • 排序功能:增加按学分、教师姓名等字段对课程进行排序的功能。
    • 统计功能:统计某位教师教授的课程数、总学分等。
    • 模糊查询:在按名称查询时,可以支持更复杂的模糊匹配。
    • 图形界面:如果学有余力,可以使用第三方库(如EasyX, GTK, Qt)将命令行界面升级为图形用户界面。

这个项目不仅是一个课程作业,更是一个可以不断迭代和完善的小型应用程序,非常适合用来练习和提升C语言编程能力。

-- 展开阅读全文 --
头像
全国计算机等级考试 c语言
« 上一篇 今天
织梦会员注册如何添加手机号验证功能?
下一篇 » 今天

相关文章

取消
微信二维码
支付宝二维码

目录[+]