广工课程设计——学生成绩统计系统

来源:互联网 发布:淘宝店铺海报尺寸多少 编辑:程序博客网 时间:2024/04/30 19:38

【前言:如题,本文中涉及的项目是去年应学妹要求帮忙写的,纯C语言,在Turbo C下编译通过。最近整理资料,觉得该项目中涉及到的结构体、链表、文件操作、断言等基础知识,以及这个小项目的函数设计和变量命名等容易忽略的知识对初学C语言的朋友应该会有帮助,所以决定发布出来。同时,给需要完成类似课程设计的学生一个参考,但是应注意理解其中的知识点,而不应复制粘贴草草了事。】

问题描述:
  学期考试结束,统计某班每个学生的平均成绩,每门课的平均成绩,并按个人平均成绩从高到低的顺序输出成绩,输出不及格人名单。输入、输出格式自定。

实现提示:
  考试课程有:高等数学、物理、外语、C语言4门课程。录入所有同学的成绩,对数据进行处理,输出所要求的内容,程序的功能主要包括以下几个方面:
① 输入成绩
② 修改记录
③ 删除记录
④ 输出成绩并按平均成绩排序,并标记平均分不及格的学生。
⑤ 界面提供上述功能选择。
⑥ 学生人数由软件根据输入的成绩记录数自动控制。
⑦ 提供输出成绩到文件以及从文件读取成绩功能。

测试数据:(自定模拟数据如下)

这里写图片描述

整体设计
  通过问题描述和对软件功能需求的分析,我们对程序的设计作出整体构思,其关键点在于数据结构的设计以及对数据的保存。本文提出一种用线性表和文件IO实现上述需求的解决方法,具体设计如下所述。
数据结构
  本文将线性表设计双向循环链表,其中结点数据域为结构体stInfo。

/// 用户信息typedef struct student{    int  id;        // 学号    char name[NAMELEN]; // 姓名    int  AMaths;    // 高数成绩    int  Physics;   // 物理成绩    int  Foreign;   // 外语成绩    int  Clan;  // C语言成绩    float GPA;  // 平均分}stInfo;
/// 用户信息结点结构体typedef struct studentNode{    stInfo data;        //<! 数据域    struct studentNode *prev;   //<! 指针域    struct studentNode *next;}stNode;

算法
  程序多处需要多链表进行查询和排序,为方便起见,本文使用遍历算法进行查询,使用冒泡法进行排序。详见附录。

文件操作
  包括文件内容的读取和写入。为方便用户直接在文件中添加学生信息、查看程序对数据处理后的结果以及便于演示,我们并没有以二进制方式操作数据,而是将数据以文本方式写入文件,因此增加了对字符串操作的代码。详见附录。

程序流程图

这里写图片描述

部分操作及细节说明

1、该系统提供五个选项,根据提示操作即可。

这里写图片描述

2、文件操作涉及的两个文件,宏定义如下

// 保存学生各科成绩#define STUDENTS_FILE "./students.txt"// 保存成绩处理完成后的结果#define SCORE_FILE "./GPA.txt"

  正常情况下,数据从文件STUDENTS_FILE和手动输入两种渠道进入链表,经过处理后再由链表流向文件STUDENTS_FILE和文件SCORE_FILE。

3、主程序负责接收用户输入的数据,并传到相应接口函数,由于标准输入(即键盘)是带缓冲的,因此需要添加下面这行代码,用以清空缓冲区。

while(getchar() != '\n') {;}

4、输入ID号和成绩时需注意:系统将ID号范围限定为1000到1999,且不能重复,成绩范围限定为0到100。

接口函数说明
相关宏定义

#define OK      1#define ERROR   0#define EXIT    2#define EXIST   1#define NOTEXIST 0

系统操作相关函数

/* * 检查用户输入的ID是否存在于链表; * 存在返回EXIST,不存在返回NOTEXIST。 */int CheckID(stNode *stHead, int id);/* * 检查用户输入的成绩是否合理; * 无返回值。*/void InputScore(int *score);/* * 初始化系统,创建链表并从STUDENTS_FILE中读取数据插入链表; * 初始化成功返回OK,否则返回ERROR。*/int InitSystem(void);/* * 等待用户输入结点数据并插入链表; * 无返回值。*/void InputRecord(void);/* * 等待用户修改结点数据; * 无返回值。*/void AlterRecord(void);/* * 等待用户删除特定结点; * 无返回值。*/void DeleteRecord(void);/* * 按系统需求对链表进行处理,并将结果输出; * 无返回值。*/void OutputRecord(void);/* * 退出系统,保存链表数据,释放内存; * 无返回值。*/void Exit(void);

链表操作相关函数

/* * 初始化一个双循环链表,*stHead为链表头指针; * 初始化成功返回OK,否则返回ERROR。*/int InitList(stNode **stHead);/* * 显示链表stHead所包含的内容; * 无返回值。*/void ShowList(stNode *stHead);/* * 将链表stHead复制为cpHead; * 复制成功返回链表头指针,否则返回NULL。*/stNode *CopyList(stNode *cpHead, stNode *stHead);/* * 将链表stHead的数据保存到文件fp中; * 无返回值。*/void SaveList(FILE *fp, stNode *stHead);/* * 释放链表stHead所占用的内存; * 无返回值。*/void FreeList(stNode *stHead);/* * 将以st作为数据域的结点插入到链表stHead的末尾; * 插入成功返回OK,否则返回ERROR。*/int InsertNode(stNode *stHead, stInfo st);/* * 删除链表stHead上相关ID号的结点; * 删除成功返回OK,否则返回ERROR。*/int DeleteNode(stNode *stHead, int id);/* * 将链表stHead相关ID号的column字段的成绩修改为score; * 修改成功返回OK,否则返回ERROR。*/int AlterNode(stNode *stHead, int id, int column, int score);/* * 将链表stHead的结点按平均分降序来排序; * 无返回值。*/void DescSort(stNode *stHead);/* * 显示链表stHead中平均分不及格的名单; * 无返回值。*/void ShowFail(stNode *stHead);

附录

/************************************************ File name : resultsMS.c Created  date : 2014-10-25 18:38 Modified date : 2014-10-27 20:07 Author : luhuadong Email  : luhuadong@163.com Description : ************************************************/#include <assert.h>#include <stdio.h>#include <stdlib.h>#include <string.h>/// 保存学生各科成绩#define STUDENTS_FILE "./students.txt"/// 保存成绩处理完成后的结果#define SCORE_FILE "./GPA.txt"#define OK  1#define ERROR   0#define EXIT    2#define EXIST   1#define NOTEXIST 0/// 用户基本信息数据长度#define STINFOLEN 80/// 结构体student中成员name的长度#define NAMELEN 32/// 用户信息typedef struct student{    int  id;    char name[NAMELEN];    int  AMaths;    int  Physics;    int  Foreign;    int  Clan;    float GPA;}stInfo;/// 用户信息结点结构体typedef struct studentNode{    stInfo data;        //<! 数据域    struct studentNode *prev;   //<! 指针域    struct studentNode *next;}stNode;stNode *stHead = NULL;int status = OK;/* 函数声明 */int CheckID(stNode *stHead, int id);void InputScore(int *score);int InitSystem(void);void InputRecord(void);void AlterRecord(void);void DeleteRecord(void);void OutputRecord(void);void Exit(void);int InitList(stNode **stHead);void ShowList(stNode *stHead);stNode *CopyList(stNode *cpHead, stNode *stHead);void SaveList(FILE *fp, stNode *stHead);void FreeList(stNode *stHead);int InsertNode(stNode *stHead, stInfo st);int DeleteNode(stNode *stHead, int id);int AlterNode(stNode *stHead, int id, int column, int score);void DescSort(stNode *stHead);void ShowFail(stNode *stHead);/* ******************************************************** */int main(void){    int mode;   // 模式选择    // 系统初始化    if(ERROR == InitSystem())    {        perror("Initialized system fail");        return -1;    }    while(OK == status)    {        // system("clear");        printf("++++++++++++++++++++++++++++++\n");        printf(" 1-输入成绩\n 2-修改记录\n 3-删除记录\n 4-输出成绩\n 5-退出\n");        printf("++++++++++++++++++++++++++++++\n>>");        while(scanf("%d", &mode) == 0)        {            while(getchar() != '\n') {;}            printf("error, try again >>\n");        }        while(getchar() != '\n') {;}        switch(mode)        {            case 1: InputRecord(); break;            case 2: AlterRecord();break;            case 3: DeleteRecord();break;            case 4: OutputRecord();break;            case 5: Exit(); break;            default: break;        }    }    return 0;}/* ******************************************************** */int CheckID(stNode *stHead, int id){    stNode *currNode = stHead->next;    while(currNode != stHead)    {        if(id == currNode->data.id) {return EXIST;}        currNode = currNode->next;    }    return NOTEXIST;}int InitSystem(void){    FILE *fp = NULL;    stInfo st;    int i=0, j=0, k=0;    char readbuf[STINFOLEN];        //<! 存放readFromFile()读取的字符串    char strStInfo[6][NAMELEN]; //<! 保存每次读取的一条记录    if(ERROR == InitList(&stHead))    {        printf("Created initial LIST failed.\n");        status = ERROR;        return ERROR;    }    fp = fopen(STUDENTS_FILE, "r");    if(NULL == fp)    {        printf("Open %s failed.\n", STUDENTS_FILE);        status = ERROR;        return ERROR;    }    while(NULL != fgets(readbuf, STINFOLEN, fp))    {        /// 每一条记录共有6个字段        for(i=0; i<6; i++)        {            while((' ' != readbuf[j]) \                    && ('\n' != readbuf[j]) \                    && ('\t' != readbuf[j]))            {                strStInfo[i][k++] = readbuf[j++];            }            strStInfo[i][k] = '\0';            j++;    //<! 跳过空格符            k = 0;        }        j = 0;        st.id       = atoi(strStInfo[0]);        strcpy(st.name, strStInfo[1]);        st.AMaths   = atoi(strStInfo[2]);        st.Physics  = atoi(strStInfo[3]);        st.Foreign  = atoi(strStInfo[4]);        st.Clan     = atoi(strStInfo[5]);        st.GPA      = 0;        if(ERROR == InsertNode(stHead, st)) { return ERROR;}    }    printf("初始化链表==>\n");    ShowList(stHead);    fclose(fp);    return OK;}void InputScore(int *score){    scanf("%d", score);    while(getchar() != '\n') {;}    while(*score < 0 || *score > 100)    {        printf("【成绩范围:0--100】\n>>");        scanf("%d", score);        while(getchar() != '\n') {;}    }    return ;}void InputRecord(void){    stInfo st;    printf("Input ID: ");    scanf("%d", &st.id);    if(st.id > 1999 || st.id < 1000)    {        printf("ID范围为1000~1999.\n");    }    if(EXIST == CheckID(stHead, st.id))    {        printf("ID重复!\n");        return ;    }    while(getchar() != '\n') {;}    printf("姓名:");    gets(st.name);    printf("高数成绩:");    InputScore(&st.AMaths);    printf("物理成绩:");    InputScore(&st.Physics);    printf("外语成绩:");    InputScore(&st.Foreign);    printf("C语言成绩:");    InputScore(&st.Clan);    if(OK == InsertNode(stHead, st)) {printf("OK\n");}    else {printf("Failed\n");}    return ;}void AlterRecord(void){    int id, column, score;    printf("Input ID: ");    scanf("%d", &id);    if(NOTEXIST == CheckID(stHead, id))    {        printf("ID不存在!\n");        return ;    }    printf("1-高数\t2-物理\t3-外语\t4-C语言\n修改科目>>");    scanf("%d", &column);    printf("修改成绩为:");    scanf("%d", &score);    if(OK == AlterNode(stHead, id, column, score)) {printf("OK\n");}    else {printf("Failed\n");}    return ;}void DeleteRecord(void){    int id;    printf("Input id: ");    scanf("%d", &id);    if(NOTEXIST == CheckID(stHead, id))    {        printf("ID不存在!\n");        return ;    }    if(OK == DeleteNode(stHead, id)) {printf("OK\n");}    else {printf("Failed\n");}    return ;}void OutputRecord(void){    FILE *fp = NULL;    stNode *cpHead = NULL;    if(ERROR == InitList(&cpHead))    {        printf("Created output LIST failed.\n");        status = ERROR;        return ;    }    CopyList(cpHead, stHead);    if(NULL == cpHead)    {        printf("Copy failed.\n");        return ;    }    DescSort(cpHead);    printf("按平均分排序==>\n");    ShowList(cpHead);    fp = fopen(SCORE_FILE, "w");    if(NULL == fp)    {        printf("Open %s failed.\n", SCORE_FILE);        return ;    }    printf("不及格学生==>\n");    ShowFail(cpHead);    SaveList(fp, cpHead);    FreeList(cpHead);    fclose(fp);    return ;}void Exit(void){    FILE *fp = fopen(STUDENTS_FILE, "w");    if(NULL == fp)    {        printf("Open %s failed.\n", STUDENTS_FILE);        return ;    }    SaveList(fp, stHead);    printf("Save to file ...\n");    FreeList(stHead);    fclose(fp);    printf("successful exit.\n");    status = EXIT;    return ;}//****************************************************int InitList(stNode **stHead){    *stHead = (stNode *)malloc(sizeof(stNode));    if(NULL != *stHead)    {        (*stHead)->prev = *stHead;        (*stHead)->next = *stHead;        return OK;    }    return ERROR;}void ShowList(stNode *stHead){    stNode *currNode = NULL;    assert(NULL != stHead);    printf("================================================================\n");    printf("学号\t姓名\t\t高数\t物理\t外语\tC语言\t平均分\n");    currNode = stHead->next;    while(currNode != stHead)    {        printf("%d\t%-8s\t%d\t%d\t%d\t%d\t%.2f\n", currNode->data.id, \                currNode->data.name, currNode->data.AMaths, \                currNode->data.Physics, currNode->data.Foreign, \                currNode->data.Clan, currNode->data.GPA);        currNode = currNode->next;    }    printf("================================================================\n");}stNode *CopyList(stNode *cpHead, stNode *stHead){    stInfo st;    stNode *currNode = NULL;    assert(NULL != cpHead && NULL != stHead);    currNode = stHead->next;    while(currNode != stHead)    {        st = currNode->data;        st.GPA = (float)(st.AMaths + st.Physics + st.Foreign + st.Clan)/4;        if(ERROR == InsertNode(cpHead, st)) {return NULL;}        currNode = currNode->next;    }    return cpHead;}void SaveList(FILE *fp, stNode *stHead){    stNode *currNode = NULL;    assert(NULL != fp && NULL != stHead);    currNode = stHead->next;    while(currNode != stHead)    {        fprintf(fp, "%d %s\t%d %d %d %d %.2f\n", currNode->data.id, \                currNode->data.name, currNode->data.AMaths, \                currNode->data.Physics, currNode->data.Foreign, \                currNode->data.Clan, currNode->data.GPA);        currNode = currNode->next;    }}void FreeList(stNode *stHead){    /// 释放链表    stNode *currNode = stHead->next;    while(currNode != stHead)    {        stHead->next = currNode->next;        free(currNode);        currNode = stHead->next;;    }    //free(currNode);   //<! 当用户信息表为空时会导致出错    free(stHead);}int InsertNode(stNode *stHead, stInfo st){    stNode *new = NULL;    assert(NULL != stHead);    new = (stNode *)malloc(sizeof(stNode));    if(NULL != new)    {        new->data = st;        new->next = stHead;        new->prev = stHead->prev;        stHead->prev->next = new;        stHead->prev = new;        return OK;    }    return ERROR;}int DeleteNode(stNode *stHead, int id){    stNode *currNode = stHead->next;    stNode *delNode = NULL;    while(currNode != stHead)    {        if(id == currNode->data.id)        {            delNode = currNode;            currNode->prev->next = currNode->next;            currNode->next->prev = currNode->prev;            currNode = currNode->prev;            free(delNode);            return OK;        }        currNode = currNode->next;    }    return ERROR;}int AlterNode(stNode *stHead, int id, int column, int score){    stNode *currNode = stHead->next;    stNode *delNode = NULL;    while(currNode != stHead)    {        if(id == currNode->data.id)        {            printf("修改前==>\n高数:%d\t物理:%d\t外语:%d\tC语言:%d\n", \                    currNode->data.AMaths, currNode->data.Physics, \                    currNode->data.Foreign, currNode->data.Clan);            if(1 == column) {currNode->data.AMaths = score;}            else if(2 == column) {currNode->data.Physics = score;}            else if(3 == column) {currNode->data.Foreign = score;}            else if(4 == column) {currNode->data.Clan = score;}            else {return ERROR;}            printf("修改后==>\n高数:%d\t物理:%d\t外语:%d\tC语言:%d\n", \                    currNode->data.AMaths, currNode->data.Physics, \                    currNode->data.Foreign, currNode->data.Clan);            return OK;        }        currNode = currNode->next;    }    return ERROR;}void DescSort(stNode *stHead){    stInfo tmp;    stNode *curr1 = stHead->next;    stNode *curr2 = stHead->next;    stNode *lastNode = stHead->prev;    for(curr1 = stHead->next; curr1 != stHead->prev; curr1 = curr1->next, lastNode = lastNode->prev)    {        for(curr2 = stHead->next; curr2 != lastNode; curr2 = curr2->next)        {            if(curr2->data.GPA < curr2->next->data.GPA)            {                tmp = curr2->data;                curr2->data = curr2->next->data;                curr2->next->data = tmp;            }        }    }}void ShowFail(stNode *stHead){    stNode *currNode = NULL;    assert(NULL != stHead);    printf("********************************\n");    printf("* 学号\t姓名\t\t平均分\n");    currNode = stHead->prev;    while(currNode->data.GPA < 60)    {        printf("* %d\t%-8s\t%.2f\n", currNode->data.id, \                currNode->data.name, currNode->data.GPA);        currNode = currNode->prev;    }    printf("********************************\n");}
0 0