news 2026/4/15 4:31:28

基于C 语言实现的(控制台)成绩管理系统

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
基于C 语言实现的(控制台)成绩管理系统

成绩管理系统

一、实验名称:成绩管理系统

二、实验学时:4 学时

三、实验目的:

  1. 熟悉并掌握 C 语言程序设计的步骤。
  2. 掌握 C 语言中函数、结构体、数组等知识和其用法。
  3. 设计小型成绩管理系统,要求实现简单的功能,一门课程的成绩管理系统包括学生成绩的录入、查询、列表等功能。

四、实验内容:

要求:

利用结构数组存储所有学生信息,最多 100 个学生。编写学生成绩管理系统,其中学生的信息有学号、姓名(汉语拼音)和分数。

完成下面函数:

1、输入学生信息函数 AddStd 实现添加学生相关信息;

2、按学号查询学生详细信息(包括成绩)QueryById;

3、成绩列表函数 ListAll 按学号排序输出学生信息;

4、输出平均分 AvgScore;

5、输出最高分 MaxScore 学生信息(需要注意的是最高分的学生可能不只一人)。

利用 while 循环实现功能界面输出,根据用户选择调用对应的功能选项。所有学生成绩信息在退出系统时以文本文件保存到文件 scores.txt(格式自定,可以是每个学生的信息和成绩占一行),在系统第一次运行时 scores.txt 被创建,每次系统运行时系统将从文件读入已保存的学生成绩信息。

提交:

代码(.c 文件)、可执行文件(exe 文件)、实验报告(word 文件)和存有数据的 scores.txt。实验报告需提供成绩录入、成绩查询、成绩列表等功能的运行结果。所有文件打包成一个压缩文件。

五、实验步骤:

  1. 定义结构体和顺序表:

考虑用结构体来表示数据元组,每个元组应包含学号、姓名(汉语拼音)和分数三个属性。同时建一个顺序表,用其中的指针指向结构体数组的元素,可实现对数据的操作。

部分代码如下:

typedef struct grade /* 定义元组信息 */ { char StuNo[20]; /* 学号,由字符串组成 */ char Name[15]; /* 姓名,由字符串组成 */ int Score; /* 成绩,char类型 */ int Flag; }Grade; typedef struct sqlist /* 定义顺序表 */ { Grade * elem; }Sqlist;

其中定义 StuNo 为学号,是 20 个字符大小的字符串,Name 为姓名,是 15 个字符大小的字符串,Score 是 int 型变量,表示成绩,最后还加了一个 int 型变量 Flag,作用是充当一个标志位,判断此处有无数据,方便程序操作。

  1. 除了题目中需要的函数外,还需要定义几个辅助函数,这里举几个比较典型的例子,详细代码见代码源文件。

(1)文件初始化函数:

void InitialFile() /* 文件初始化方法 */ { FILE * pf; if ( (pf = fopen( "scores.txt", "a" ) ) == NULL ) /* 打开操作不成功 */ { printf( "错误:数据文件打开失败!n" ); return; /* 结束程序的执行 */ } fclose( pf ); return; }

作用:在每次程序开始时都执行一次,使用“a”方法打开文件,可以实现没有该文件自动穿件该文件,并且当该文件存在时可以不用清除其中的内容。

(2)文件读取函数:

void GetSqlist( int * mm, int * nn, Grade * b, Sqlist * a ) /* 通过现有文件创建一个顺序表 */ { FILE * pf; int tempc; int tempcc; char temps[20]; char tempss[15]; int i; int count = 0; a - > elem = b; /* 初始化 */ if ( (pf = fopen( "scores.txt", "r" ) ) == NULL ) /* 打开操作不成功 */ { printf( "错误:文件打开失败!" ); return; /* 结束程序的执行 */ } for ( i = 0; i < *nn; i++ ) { (a - > elem + i) - > Flag = 0; } for ( i = 0; i < *nn; i++ ) { tempc = fgetc( pf ); if ( tempc == EOF ) { printf( "顺序表创建完成!n" ); break; } if ( tempc == '#' ) { tempc = fgetc( pf ); if ( tempc != '#' ) { count++; fseek( pf, -1, SEEK_CUR ); fgets( temps, 20, pf ); if ( 1 ) { strcpy( (a - > elem + i) - > StuNo, temps ); fseek( pf, 3, SEEK_CUR ); fgets( tempss, 15, pf ); strcpy( (a - > elem + i) - > Name, tempss ); fseek( pf, 4, SEEK_CUR ); fscanf( pf, "%d ", &tempcc ); /* */ (a - > elem + i) - > Score = tempcc; (a - > elem + i) - > Flag = 1; } } } } *mm = count; return; }

作用:在程序开始时执行此操作,可以实现将文件中的数据读取到当前内存中的效果,方便后续处理。

(3)结构体排序操作:

void SortSqlist(Sqlist * a, int * mm) //BUG { int i, j; int tempc; char temps[20]; char tempss[15]; for (i = 0; i < 20; i++) { temps[i] = ' '; } for (i = 0; i < 15; i++) { tempss[i] = ' '; } for (i = 0; i < *mm; i++) { for (j = 0; j < *mm - 1; j++) { if (strcmp((a - >elem + j) - >StuNo, (a - >elem + j + 1) - >StuNo) > 0) { strcpy(temps, (a - >elem + j) - >StuNo); strcpy((a - >elem + j) - >StuNo, (a - >elem + j + 1) - >StuNo); strcpy((a - >elem + j + 1) - >StuNo, temps); strcpy(tempss, (a - >elem + j) - >Name); strcpy((a - >elem + j) - >Name, (a - >elem + j + 1) - >Name); strcpy((a - >elem + j + 1) - >Name, tempss); tempc = (a - >elem + j) - >Score; (a - >elem + j) - >Score = (a - >elem + j + 1) - >Score; (a - >elem + j + 1) - >Score = tempc; } } } }

作用:对当前数据表中元组按学号从小到大进行排序,使用的是冒泡排序法。

(4)写入文件函数

void WriteFile( Sqlist * a, int * mm ) { int i; FILE * pf; if ( (pf = fopen( "scores.txt", "w" ) ) == NULL ) /* 打开操作不成功 */ { printf( "错误:文件打开失败!" ); return; /* 结束程序的执行 */ } for ( i = 0; i < *mm; i++ ) { if ( (a - > elem + i) - > Flag == 1 ) { fprintf( pf, "#%-20s##%-15s###%-5dn", (a - > elem + i) - > StuNo, (a - > elem + i) - > Name, (a - > elem + i) - > Score ); } } fclose( pf ); return; }

作用:该系统实现的逻辑是:开始时从文件中读取数据到内存,之后对数据表的操作直接在内存中进行,当数据有变动或结束程序时,重新把内存中的数据按一定格式写入文件,这个函数就是写入文件用的。

  1. 程序主要功能的实现:

(1)添加学生信息

void AddStu(Sqlist * a, int * mm, int * nn) { char newStuNo[20]; char newName[15]; int * newScore; int i; if ( * mm == *nn) //超出容量,返回值为0,表示出错 { printf("出错:超出数据表容量!n"); //提示:超出容量,出错 return; } GetInfo(newStuNo, newName, newScore); for (i = 0; i < *nn; i++) { if ((a - >elem + i) - >Flag == 0) { strcpy((a - >elem + i) - >StuNo, newStuNo); strcpy((a - >elem + i) - >Name, newName); (a - >elem + i) - >Score = *newScore; (a - >elem + i) - >Flag = 1; * mm = *mm + 1; break; } } printf("n信息添加成功!n"); return; }

作用:从键盘输入学生信息,并将其添加到内存中的数据表。

(2)按学号查询学生信息:

void QuertById( Sqlist *a, int *mm ) /*按ID查找操作 */ { char inputStuNo[20]; int i; for ( i = 0; i < 20; i++ ) { inputStuNo[i] = ' '; } GetStuNo( inputStuNo ); for ( i = 0; i < 20; i++ ) { if ( inputStuNo[i] == '0' ) { inputStuNo[i] = ' '; } } inputStuNo[i - 1] = '0'; printf( "n" ); printf( "学号 " ); printf( "姓名 " ); printf( "成绩n" ); for ( i = 0; i < *mm; i++ ) { if ( (strcmp( inputStuNo, (a->elem + i)->StuNo ) == 0) && ( (a->elem + i)->Flag == 1) ) { printf( "%-20s", (a->elem + i)->StuNo ); printf( "%-15s", (a->elem + i)->Name ); printf( "%-5d", (a->elem + i)->Score ); printf( "n" ); } } printf( "nn查询完成!nn" ); }

作用:实现按学号查询功能。从键盘中输入学号,可以在屏幕上输出相关的学生信息(包括学号、姓名和成绩)。

(3)按学号排序输出学生信息:

void ListAll(int * mm, int * nn, Sqlist * a) { SortSqlist(a, mm); int i; printf("n"); printf("学号 "); printf("姓名 "); printf("成绩n"); for (i = 0; i < *nn; i++) { if ((a - >elem + i) - >Flag == 1) { printf("%-20s", (a - >elem + i) - >StuNo); printf("%-15s", (a - >elem + i) - >Name); printf("%-5d", (a - >elem + i) - >Score); printf("n"); } } printf("n"); return; }

作用:首先对结构体数组按学号排序,再遍历数组输出所有元组信息。

(4)输出平均分

void AvgScore( int *mm, int*nn, Sqlist *a ) { int i; int s = 0; float avg; for ( i = 0; i < *mm; i++ ) { s += (a->elem + i)->Score; } avg = (float) s / (*mm); printf( "平均成绩为:%.2f", avg ); printf( "n" ); return; }

作用:输出当前数据表中所有元组的成绩的平均值,精确到小数点后两位。直接遍历数组,再按照平均值公式计算即可。

(5)输出最高分学生信息

void MaxScore(int * mm, int * nn, Sqlist * a) { Grade temp; int i; int Max = -100; for (i = 0; i < *mm; i++) { if (Max < (a - >elem + i) - >Score) { Max = (a - >elem + i) - >Score; } } printf("n"); printf("最高分为:%d", Max); printf("n"); printf("学号 "); printf("姓名 "); printf("成绩n"); for (i = 0; i < *mm; i++) { if ((a - >elem + i) - >Score == Max) { printf("%s", (a - >elem + i) - >StuNo); printf("%s", (a - >elem + i) - >Name); printf("%d", (a - >elem + i) - >Score); printf("n"); } } return; }

作用:输出最高分学生信息,如果有多个学生都是最高分,则这些学生信息都会被输出。函数实现的逻辑是,先遍历一遍数组,找出最高分,再遍历一遍数组,只要某学生成绩为最高分,就输出这个学生的信息。

(6)除了题目要求的功能以外,本程序还实现了删除学生信息和显示当前数据表状态的功能。

void DelById(Sqlist * a, int * mm) { char inputStuNo[20]; int i; for (i = 0; i < 20; i++) { inputStuNo[i] = '0'; } GetStuNo(inputStuNo); //BUG for (i = 0; i < 20; i++) { if (inputStuNo[i] == '0') { inputStuNo[i] = ' '; } } inputStuNo[i - 1] = '0'; for (i = 0; i < *mm; i++) { if (strcmp(inputStuNo, (a - >elem + i) - >StuNo) == 0) { (a - >elem + i) - >Flag = 0; } } * mm = *mm - 1; printf("n删除成功!n"); return; }

作用:按学号删除函数,原理是通过修改元组的 Flag 标志位来实现删除。并且下一次再加入新元组时,该位置会被替代,从而实现了不浪费空间的效果。

同时,在主函数中定义了两个 int 型变量 x,y,一个用于表示数据表的最大容量,一个用于表示当前容量,这两个变量会在函数操作中不断变化,从而实现可以实时查看数据表状态和防止数据溢出的效果。

  1. 主函数循环体的实现
for (;;) { printf("欢迎使用成绩管理系统,请选择功能: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("按0:退出程序n"); printf("n"); scanf("%d", &a); switch (a) { case 0: { WriteFile(aa, mm); printf("感谢您的使用!n"); return 0; } case 1: { AddStu(aa, mm, nn); getchar(); WriteFile(aa, mm); break; } case 2: { QuertById(aa, mm); break; } case 3: { ListAll(mm, nn, aa); WriteFile(aa, mm); break; } case 4: { AvgScore(mm, nn, aa); break; } case 5: { MaxScore(mm, nn, aa); break; } case 6: { DelById(aa, mm); WriteFile(aa, mm); break; } case 7: { printf("当前数据容量:%dn", *mm); printf("最大数据容量:%dn", *nn); break; } case 8: { WriteFile(aa, mm); printf("保存成功!n"); break; } default: { printf("非法命令!n"); printf("n"); break; } } }

作用:实现程序界面的循环。通过一个无条件的 for 循环和 switch 语句来实现各个功能。

六、实验结果分析:

测试平台:

Windows 10 64 位

C-Free 5.0

  1. 程序主页面如下:

图 1.程序主界面图

  1. 添加学生信息:

图 2.添加学生信息界面图

通过相同的方法添加其他几个学生信息,最后写入文件的效果为:

图 3.文件信息图

数据在文件中按图 3 所示的格式进行存储,方便读写的同时方法阅读。

  1. 按学号查找信息

图 4.查询界面图

  1. 按学号排序查看所有成绩信息

图 5.查看所有成绩界面图

  1. 查看成绩平均分

图 5.查看成绩平均分界面图

  1. 查看最高分学生信息

图 6.查看最高分学生信息界面图

发现可以显示多个成绩相同的学生的信息。

  1. 按学号删除成绩信息

图 7.删除学生成绩信息界面图

删之后查看所有学生信息,发现正确:

图 8.删除信息后查看所有学生信息界面图

  1. 查看当前数据表状态

图 9.查看当前数据表状态界面图

  1. 保存当前数据到文件

图 10.文件保存成功提示图

  1. 退出程序

图 11.程序退出界面示意图

七、实验结论:

1、C 语言可以实现简单成绩管理系统;

2、模块化程序设计需要先规划好程序的各个模块功能;

3、调试是程序设计中必不可少的一环。

八、总结及心得体会:

1、要善于使用调试功能,这会让程序设计事半功倍;

2、多掌握编程语言的语法和库函数,可以让程序实现更多功能;

3、在编程前一定要先在纸上记录大纲。

九、对本实验的改进建议:

1、可以多设置几个难度差不多的题目供同学们选择。

♻️ 资源

大小:76.2KB

➡️资源下载:https://download.csdn.net/download/s1t16/87404243

注:更多内容可关注微信公众号【神仙别闹】,如当前文章或代码侵犯了您的权益,请私信作者删除!

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/13 14:47:27

LyricsX:macOS平台快速上手指南与核心功能详解

LyricsX&#xff1a;macOS平台快速上手指南与核心功能详解 【免费下载链接】LyricsX &#x1f3b6; Ultimate lyrics app for macOS. 项目地址: https://gitcode.com/gh_mirrors/lyr/LyricsX LyricsX是macOS系统上功能强大的歌词显示工具&#xff0c;能够智能识别播放中…

作者头像 李华
网站建设 2026/4/13 16:50:43

【二维稳态热传导偏微分方程、用于求解具有指定边界温度的方形壁中各个节点的温度值】采用高斯-塞德尔迭代法计算节点温度研究附Matlab代码

✅作者简介&#xff1a;热爱科研的Matlab仿真开发者&#xff0c;擅长数据处理、建模仿真、程序设计、完整代码获取、论文复现及科研仿真。&#x1f34e; 往期回顾关注个人主页&#xff1a;Matlab科研工作室&#x1f34a;个人信条&#xff1a;格物致知,完整Matlab代码及仿真咨询…

作者头像 李华
网站建设 2026/4/13 14:32:07

【发】多跳收集-传输无线传感器网络(WSNs)中的性能增强:在窃听者和硬件噪声存在的情况下采用路径选择方法附Matlab代码

✅作者简介&#xff1a;热爱科研的Matlab仿真开发者&#xff0c;擅长数据处理、建模仿真、程序设计、完整代码获取、论文复现及科研仿真。&#x1f34e; 往期回顾关注个人主页&#xff1a;Matlab科研工作室&#x1f34a;个人信条&#xff1a;格物致知,完整Matlab代码及仿真咨询…

作者头像 李华