项目要求:
1、结构体 2、分文件 3、make编译
(1)系统运行时,打开如下界面。列出系统帮助菜单(即命令菜单),提示输入命令。
(2) 开始时还没有录入成绩,除了输入命令T进行成绩录入,输入其他命令无法列出成绩。应提示“成绩表为空!请先使用命令 T 录入学生成绩。”
(3)输入命令 T,调用Type子函数录入成绩。界面提示输入学生人数,提示输入n名学生的3门课成绩,列出成绩单的表头“学号 语文 数学 英语”,提示学号:1。输入完毕后,按回车结束。Type子函数调用结束,返回。提示输入命令。
(4)输入命令 L ,调用List子函数输出成绩表。List子函数调用结束,返回。提示输入命令。
(5)输入命令 A ,调用Average子函数计算平均分,提示“平均分已计算。请使用命令L查看。” Average子函数调用结束,返回。提示输入命令。再次输入命令 L ,调用List子函数输出成绩表。List子函数调用结束,返回。提示输入命令。
(6)输入命令 P ,调用Sort子函数将各学生记录按平均分由高到低排序,提示“完成排序。请使用命令L查看。” Sort子函数调用结束,返回。提示输入命令。再次输入命令 L ,调用List子函数输出成绩表。List子函数调用结束,返回。提示输入命令。
(7)输入命令 S ,调用Search子函数查询学生成绩,提示“输入要查询的学生学号”。输入2 ¿ 找到2号学生的成绩并输出。Search子函数调用结束,返回。提示输入命令。
(8)输入命令C,执行清屏函数语句system("clear");清除屏幕的所有内容。提示输入命令。
(9)输入命令H,调用Help子函数显示帮助菜单。Help子函数调用结束,返回。提示输入命令。
(10)输入命令Q,退出系统。
注意:
(1)输出数组元素时,要将学号单独处理,输出为整数(即保留0位小数)。同理,在计算成绩时也要将第1列的学号撇开,只计算第2列之后的。成绩保留1位小数。
(2)学生人数n贯穿始终,通过n的值判断当前命令的子函数是否能够调用执行。例如:当n=0时,说明还没有录入成绩。而一旦输入命令T,也即调用Type子函数录入了成绩,则n的值就不再是0。当n!=0时,就可以进行其他的成绩操作,但不能再执行录用成绩的操作。所以当用户输入的命令无法执行时,应当给出提示。
项目代码:
头文件:
头文件一般不声明变量,可以在其他源文件内先声明变量,在头文件中外部引用,在其他子函数内引用头文件。
因为定义的结构体和声明的外部变量都在头文件中,所以无需在每个函数调用时显式地传递这些参数或变量(外部引用------牵一发而动全身)。
#ifndef __HEAD_H_
#define __HEAD_H_
typedef struct student
{
int num;//学号
float chinese;
float math;
float english;
}STU;//存储学生信息
STU SCORE[100];
extern float average[100];//平均数数组
extern int num; // 全部变量学生个数
extern char n; // 菜单编号
void menu();
void type();
void help();
void list();
void sort();
void serch();
void clean();
void Average();
#endif
主函数:
主要使用switch case分支语句来判断是否输入正确命令,并调用子函数
#include <stdio.h>
#include "head.h"
int num; // 全部变量学生个数
char n; // 菜单编号
int main()
{
menu();
n=toupper(n);
while (n != 'Q'||n!='q')//输入Q时退出程序
{
printf("请输入指令=");
scanf(" %c", &n);
switch (n)
{
case 'H':
case 'h':
help();
break;
case 'T':
case 't':
if (num == 0)
type();
else
printf("你已经录入学生信息,请勿重复录入\n");
break;
case 'A':
case 'a':
if (num > 0)
Average();
else
printf("成绩表为空!请先使用命令 T 录入学生成绩。\n");
break;
case 'L':
case 'l':
if (num > 0)
list();
else
printf("成绩表为空!请先使用命令 T 录入学生成绩。\n");
break;
case 'P':
case 'p':
if (num > 0)
sort();
else
printf("成绩表为空!请先使用命令 T 录入学生成绩。\n");
break;
case 'S':
case 's':
if (num > 0)
serch();
else
printf("成绩表为空!请先使用命令 T 录入学生成绩。\n");
break;
case 'C':
case 'c':
clean();
break;
case 'Q':
case 'q':
printf("退出程序\n");
return 0;
default:
printf("输入错误,请重新输入!\n");
break;
}
}
return 0;
}
创建菜单:
创建菜单的子函数比较简单,可以新封装一个函数专门用来输出*号,这样看起来干净清爽很多。
注意对齐!!!
#include<stdio.h>
#include"head.h"
void str()
{
for(int i=0;i<50;i++)
printf("*");
printf("\n");
}//*号输出机
void menu()
{
str();
printf(" * 学生管理系统--帮助菜单 *\n");
str();
printf(" * H = 显示帮助菜单 *\n");
printf(" * T = 成绩录入 *\n");
printf(" * A = 计算学生平均分 *\n");
printf(" * L = 列出成绩表 *\n");
printf(" * P = 按平均成绩由高到低排序 *\n");
printf(" * S = 按学号查询学生成绩 *\n");
printf(" * C = 清屏 *\n");
printf(" * Q = 退出系统 *\n");
str();
printf(" * Copyright <C> 2024.07.11 by 靳长庚 *\n");
str();
}
帮助菜单
#include<stdio.h>
#include"head.h"
extern void str();
void help()
{
str();
printf(" * 学生管理系统--帮助菜单 *\n");
str();
printf(" * H = 显示帮助菜单 *\n");
printf(" * T = 成绩录入 *\n");
printf(" * A = 计算学生平均分 *\n");
printf(" * L = 列出成绩表 *\n");
printf(" * P = 按平均成绩由高到低排序 *\n");
printf(" * S = 按学号查询学生成绩 *\n");
printf(" * C = 清屏 *\n");
printf(" * Q = 退出系统 *\n");
str();
printf(" * Copyright <C> 2024.07.11 by 靳长庚 *\n");
str();
}
成绩录入
输入命令T后,提示输入学生人数,输出表头。
printf("请输入学生人数:");
scanf(" %d",&num);
printf("请输入%d个学生的3门课成绩:\n",num);
printf("学号\t语文\t数学\t英语\n");
使用for循环遍历输入学生成绩,同时提供学号提示,并赋值给结构体数组。(在排序和输出成绩表时使用。)
#include<stdio.h>
#include"head.h"
void type()
{
printf("请输入学生人数:");
scanf(" %d",&num);
printf("请输入%d个学生的3门课成绩:\n",num);
printf("学号\t语文\t数学\t英语\n");
for(int i=0;i<=num-1;i++)
{
printf("%d",i+1);//提示学号
SCORE[i].num=i+1;
scanf("%f %f %f",&SCORE[i].chinese,&SCORE[i].english,&SCORE[i].math);
}
printf("成绩录入完毕\n");
}
计算学生平均分
定义了一个平均数的数组,同时在头文件内声明外部引用该平均数数组,简化函数传参。
使用for循环,循环计算每一个学生的平均分
#include<stdio.h>
#include"head.h"
float average[100];//平均数数组
void Average()
{
for(int i=0;i<num;i++)
average[i] = (SCORE[i].chinese+SCORE[i].english+SCORE[i].math)/3 ;
printf("平均分已计算。请使用命令L查看。\n");
}
排序
当没有计算平均分时,无法进行排序,并给出提示,回到主函数。
使用冒泡排序,将平均分较高的学生往前冒泡,同时也需要交换学号。(对应成绩录入时写入学号/🙂)
#include<stdio.h>
#include"head.h"
void sort()
{
if (average[0]!=0)
{
float *p=average;
for(int i=0;i<num-1;i++)
{
for(int j=0;j<num-1-i;j++)
{
if(p[j+1]>p[j])
{
STU temp = SCORE[j];//定义结构体变量,分别存入对应成员变量
SCORE[j] = SCORE[j + 1];
SCORE[j+1] = temp;
float temp1=p[j];
p[j]=p[j+1];
p[j+1]=temp1;
}
}
}
printf("排序已完成,请按L查看。\n");
}else if(average[0]==0)
{
printf("请先输入命令A计算平均分。\n");
return;
}
}
列出成绩表
成绩表采用多层if结构:如果没有计算平均分(平均分数组内所有元素都是0,以此来当if条件语句),输出表头不应该带平均分那一列,如果进行了平均分的计算后,则输出列应该有平均分。
采用for循环,循环遍历输出结构体数组成员。
/*输出成绩表*/
#include<stdio.h>
#include"head.h"
extern int s;//引用sort中定义的s来判断是否执行了排序函数
void list()
{
if(average[0]==0)
{
printf("学生成绩如下:\n");
printf("学号\t语文\t数学\t英语\n");
for(int i=0;i<=num-1;i++)
{
printf("%d",SCORE[i].num);
printf("\t%0.1f\t%0.1f\t%0.1f\n",SCORE[i].chinese,SCORE[i].english,SCORE[i].math);
}
}
else if(average[0]!=0)
{
printf("学号\t语文\t数学\t英语\t平均分\n");
for(int i=0;i<=num-1;i++)
{
printf("%d",SCORE[i].num);
printf("\t%0.1f\t%0.1f\t%0.1f\t%0.1f\n",SCORE[i].chinese,SCORE[i].english,SCORE[i].math,average[i]);
}
}
}
查询学生成绩
定义一个变量id,用来向用户索取要查询的学生号,进入循环(当输入错误时循环向用户索取学生id),当输入id在学生人数范围内时,对学生id进行遍历,查找到符合的学号时输出该学生的成绩并返回主函数等待命令。
#include<stdio.h>
#include"head.h"
int id=0;
void serch()
{
printf("输入要查询的学生学号:");
scanf(" %d",&id);
while(1)
{
if (id >= 1 && id <= num)
{
for(int i=0;i<num;i++)
{
if(id==SCORE[i].num)
{
printf("学号\t语文\t数学\t英语\t平均分\n");
printf("%d",SCORE[i].num);
printf("\t%0.1f\t%0.1f\t%0.1f\t%0.1f\n",SCORE[i].chinese,SCORE[i].english,SCORE[i].math,average[i]);
return;
}
}
}else
{
printf("输入错误,查无此人,请重新输入:");
scanf(" %d",&id);
}
}
}
清屏
使用system("clear")函数,注意头文件是<stdlib.h>
#include<stdio.h>
#include <stdlib.h>
void clean()
{
system("clear");
return;
}
make编译
CC=gcc
OBJS=main.o menu.o help.o type.o list.o average.o sort.o serch.o clean.o
CFLAGS=-c -g -Wall
main: $(OBJS)
$(CC) $^ -o $@
%.o: %.c
$(CC) $(CFLAGS) $< -o $@
.PHONY: clean
clean:
$(RM) -r *.o main
效果展示
C语言-学生管理系统的实现