C语言实现一个列表式的学生信息管理系统(完善)
程序员文章站
2022-05-05 23:15:58
...
http://blog.csdn.net/morixinguan/article/details/77489633
上节,我们实现了学生信息管理系统的大多数功能,但还有两个功能没有实现,就是学生信息修改还有学生信息删除了。当然,程序中依然存在诸多的BUG,比如,scanf和getchar函数就是一对冤家,如果用了scanf,再调用getchar,就会出现所谓的输入缓冲区问题,导致程序一闪而过。然而解决这种问题的唯一方法就是使用fflush函数,对输入缓冲区,输出缓冲区,出错缓冲区进行刷新。下面是对多数明显的程序BUG进行修复,以及添加了删除和修改的功能。但可能存在一些未发觉的BUG,需要进行程序的压力测试才能得知,但如图所示的基本功能已经完全可以正常工作了。
该项目实现的效果如下:
那么这里面用到了window上的那些知识点才可以做到这样的效果呢?上节博文已经给大家介绍了两个博客。当然大家也可以去搜索这本pdf教程:
叫做C/C++控制台界面编程,可以学习下,写出炫酷的控制台程序。
接下来,我们来看下代码的具体实现:
/*
Copyright (C) 2007 The Windows console C Open Source Project
AUTHOR: Y.X.YANG
date: 2017年8月23日
version: 2.0
C runtime environment : Windows DevC++ And all Windows development Software
*/
#include <stdio.h>
#include <Windows.h>
#include <conio.h>
#include <stdlib.h>
#include <unistd.h>
#include <tchar.h>
#define NR(x) (sizeof(x)/sizeof(x[0]+0))
#define TITLE "学生信息管理系统"
#define AUTHOR "作者:杨源鑫"
#define DATE "日期:2017年8月23日 version2"
#define SIZE 100
//在终端上打印信息
#define Print_Info_To_console(str,hOut,pos,x,y,color_type) \
SetConsoleTextAttribute(hOut, color_type); \
pos.X = x; \
pos.Y = y ; \
SetConsoleCursorPosition(hOut,pos); \
printf("%s",str);
//清屏
#define ClearScreen() \
system("cls");
//定义枚举Keyboard的键值数据
enum
{
UP = 72,
DOWN = 80 ,
LEFT = 75 ,
RIGHT = 77 ,
ENTER = 13 ,
ESC = 27 ,
};
//存储学生信息的结构体
struct student
{
char name[20] ; //名字
int id ; //学生ID
float score ; //分数
};
//定义要显示的菜单
char *menu[] =
{
"*学生信息添加*",
"*学生信息查找*",
"*学生信息打印*",
"*学生信息修改*",
"*学生信息删除*",
"*学生信息保存*",
"*学生信息导入*",
"* 退出 *",
};
//窗口初始化
void HANDLE_init(HANDLE hOut);
//显示菜单
void showmenu(HANDLE hOut ,char **menu , int size , int index) ;
//获取用户输入
int get_userinput(int *index , int size) ;
//学生信息添加
void stu_add(HANDLE hOut);
//学生信息打印
void stu_show(HANDLE hOut);
//学生信息查找
void stu_search(HANDLE hOut);
//学生信息保存
void stu_save(HANDLE hOut);
//学生信息导入
void stu_load(HANDLE hOut);
//学生信息修改
void stu_modefi(HANDLE hOut);
//学生信息删除
void stu_delete(HANDLE hOut);
//学生的个数
int stucount ;
//定义一个数组,用于存储学生信息
struct student array[SIZE] = {0};
//定义设置光标结构体变量
CONSOLE_CURSOR_INFO cci;
//定义默认的坐标位置
COORD pos = {0,0};
int main()
{
int i;
int ret ;
int index = 0 ;
HANDLE hOut;
hOut = GetStdHandle(STD_OUTPUT_HANDLE);
HANDLE_init(hOut);
while(1)
{
showmenu(hOut , menu , NR(menu) , index);
ret = get_userinput(&index , NR(menu));
if(ret == ESC)
break ;
if(ret == ENTER)
{
switch(index)
{
case 0: stu_add(hOut) ; break ; //学生信息添加
case 1: stu_search(hOut);break ; //学生信息查找
case 2: stu_show(hOut); break ; //学生信息打印
case 3: stu_modefi(hOut); break ; //学生信息修改
case 4: stu_delete(hOut); break ; //学生信息删除
case 5: stu_save(hOut); break ; //学生信息保存
case 6: stu_load(hOut); break ; //学生信息导入
case 7: ClearScreen();return 0 ; //退出学生信息管理系统
}
}
}
//关闭窗口句柄
CloseHandle(hOut);
return 0;
}
//窗口初始化
void HANDLE_init(HANDLE hOut)
{
SetConsoleTitleA(TITLE);
//获取当前的句柄---设置为标准输出句柄
//获取光标信息
GetConsoleCursorInfo(hOut, &cci);
//设置光标大小
cci.dwSize = 1;
//设置光标不可见 FALSE
cci.bVisible = 0;
//设置(应用)光标信息
SetConsoleCursorInfo(hOut, &cci);
}
//菜单初始化
void showmenu(HANDLE hOut ,char **menu , int size , int index)
{
int i ;
ClearScreen();
Print_Info_To_console(TITLE,hOut,pos,30,0,FOREGROUND_GREEN | 0x8);
Print_Info_To_console(AUTHOR,hOut,pos,32,1,FOREGROUND_GREEN | 0x8);
Print_Info_To_console(DATE,hOut,pos,25,2,FOREGROUND_GREEN | 0x8);
Print_Info_To_console("请按↑↓←→按键选择,并用Enter按键确认",hOut,pos,20,20,FOREGROUND_GREEN | 0x8);
for(i = 0 ; i < size ; i++)
{
//如果i==index表示在当前选项的位置,默认初始化显示是第一项,显示为红色,
//当按下上下按键选择的时候,光标会移动,也就看到了列表选择的现象
if(i == index){
Print_Info_To_console(menu[i],hOut,pos,30,i+5,FOREGROUND_RED | 0x8);
}
else{
Print_Info_To_console(menu[i],hOut,pos,30,i+5,FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE | 0x8);
}
}
//刷新标准输出缓冲区
fflush(stdout);
}
//获取用户输入的接口
int get_userinput(int *index , int size)
{
int ch ;
fflush(stdin);
ch = getch();
switch(ch)
{
//上
//如果选择上,那么光标向上移动
case UP : if(*index > 0) *index -= 1 ; break;
//下
//如果选择下,那么光标向下移动
case DOWN :if(*index < size -1) *index += 1 ; break;
//左
case LEFT:
case 97:return 0 ;
//右
case RIGHT:return 0 ;
//回车
case ENTER: return ENTER ;
//ESC
case ESC: return ESC ;
}
return 0 ;
}
//学生信息添加
void stu_add(HANDLE hOut)
{
ClearScreen();
if(stucount >= SIZE){
Print_Info_To_console("学生信息已经满了\n",hOut,pos,30,0,FOREGROUND_RED | 0x8);
}
Print_Info_To_console("学生信息添加\n",hOut,pos,30,0,FOREGROUND_GREEN | 0x8);
printf("学生姓名:");
scanf("%s" , array[stucount].name);
printf("\n学生ID:");
scanf("%d" , &(array[stucount].id));
printf("\n学生成绩:");
scanf("%f" , &(array[stucount].score));
stucount++ ;
//清掉输入缓冲区中的\n
getchar();
fflush(NULL);
}
//学生信息打印
void stu_show(HANDLE hOut)
{
int i ;
ClearScreen();
fflush(stdin);
fflush(stdout);
Print_Info_To_console("学生信息打印\n",hOut,pos,30,0,FOREGROUND_GREEN | 0x8);
for(i = 0 ; i < stucount ; i++)
{
SetConsoleTextAttribute(hOut, FOREGROUND_RED| 0x8);
pos.X = 1;
pos.Y = i+4 ;
SetConsoleCursorPosition(hOut,pos);
printf("ID:%2d ",array[i].id);
printf("姓名:%s ",array[i].name);
printf("分数:%4.1f ",array[i].score);
}
fflush(stdout);
Print_Info_To_console("Please press any key to continue ... \n",hOut,pos,0,20,FOREGROUND_GREEN | 0x8);
getchar();
}
//查找ID
static void search_id(HANDLE hOut,int id)
{
ClearScreen();
Print_Info_To_console("查找到学生的信息\n",hOut,pos,30,0,FOREGROUND_GREEN | 0x8);
fflush(stdout);
int i ,j ,flag = 0;
for(i = 0 , j = 0 ; i < stucount ; i++)
{
if(array[i].id == id)
{
flag = 1 ;
SetConsoleTextAttribute(hOut, FOREGROUND_RED| 0x8);
pos.X = 1;
pos.Y = j+4 ;
SetConsoleCursorPosition(hOut,pos);
printf("ID:%2d ",array[i].id);
printf("姓名:%s ",array[i].name);
printf("分数:%f ",array[i].score);
j++ ;
}
}
if(flag == 0)
{
Print_Info_To_console("找不到该学生的ID,请按任意按键返回主菜单!\n",hOut,pos,0,20,FOREGROUND_RED | 0x8);
getchar();
}
if(flag == 1)
{
fflush(stdout);
Print_Info_To_console("Please press any key to continue ... \n",hOut,pos,0,20,FOREGROUND_GREEN | 0x8);
getchar();
}
}
//查找姓名
static void search_name(HANDLE hOut,const char *name)
{
ClearScreen();
Print_Info_To_console("查找到学生的信息\n",hOut,pos,30,0,FOREGROUND_GREEN | 0x8);
fflush(stdout);
int i , j , flag = 0;
for(i = 0 , j = 0; i < stucount ; i++)
{
if(strcmp(array[i].name , name) == 0)
{
flag = 1 ;
SetConsoleTextAttribute(hOut, FOREGROUND_RED| 0x8);
pos.X = 1;
pos.Y = j+4 ;
SetConsoleCursorPosition(hOut,pos);
printf("ID:%2d ",array[i].id);
printf("姓名:%s ",array[i].name);
printf("分数:%f ",array[i].score);
j++ ;
}
}
if(flag == 0)
{
Print_Info_To_console("找不到该学生的姓名,请按任意按键返回主菜单!\n",hOut,pos,0,20,FOREGROUND_RED | 0x8);
getchar();
}
if(flag == 1)
{
fflush(stdout);
Print_Info_To_console("Please press any key to continue ... \n",hOut,pos,0,20,FOREGROUND_GREEN | 0x8);
getchar();
}
}
//学生信息查找
void stu_search(HANDLE hOut)
{
char ch ;
int id ;
char name[30] ;
repeat:
ClearScreen();
Print_Info_To_console("学生信息查找\n",hOut,pos,30,0,FOREGROUND_GREEN | 0x8);
Print_Info_To_console("请选择按什么方式查找学生信息 :\n",hOut,pos,20,0,FOREGROUND_GREEN | 0x8);
Print_Info_To_console(" 1.ID \n",hOut,pos,10,1,FOREGROUND_GREEN | 0x8);
Print_Info_To_console(" 2.NAME \n",hOut,pos,10,2,FOREGROUND_GREEN | 0x8);
fflush(stdout);
//获取要输入的信息
ch = getch();
if(ch == '1')
{
ClearScreen();
Print_Info_To_console("请输入学生ID: ",hOut,pos,0,1,FOREGROUND_GREEN | 0x8);
fflush(stdout);
scanf("%d" , &id);
getchar();
if(id < 0)
{
getchar();
Print_Info_To_console("请入ID有误,请按任意键重新选择输入\n",hOut,pos,0,20,FOREGROUND_RED | 0x8);
getchar();
goto repeat;
}
search_id(hOut,id);
}
if(ch == '2')
{
printf("请输入学生NAME: ");
fflush(stdout);
scanf("%s" , name);
getchar();
search_name(hOut,name);
}
if(ch != '1' && ch != '2')
{
goto repeat;
}
}
//学生信息保存
void stu_save(HANDLE hOut)
{
FILE *filp = NULL ;
char ch ;
char Path[30] ;
repeat1:
ClearScreen();
Print_Info_To_console("学生信息保存\n",hOut,pos,30,0,FOREGROUND_GREEN | 0x8);
Print_Info_To_console("请选择按什么方式保存学生信息 :\n",hOut,pos,20,0,FOREGROUND_GREEN | 0x8);
Print_Info_To_console(" 1.追加 \n",hOut,pos,10,1,FOREGROUND_GREEN | 0x8);
Print_Info_To_console(" 2.覆盖 \n",hOut,pos,10,2,FOREGROUND_GREEN | 0x8);
fflush(stdout);
ch = getch();
ClearScreen();
Print_Info_To_console("请输入保存文件名:\n",hOut,pos,0,1,FOREGROUND_GREEN | 0x8);
scanf("%s" , Path);
getchar();
if(ch == '1')
{
filp = fopen(Path , "a+");
if(NULL == filp)
{
Print_Info_To_console("文件打开失败 \n",hOut,pos,0,20,FOREGROUND_RED | 0x8);
Print_Info_To_console("请按任意键重新选择输入 \n",hOut,pos,0,21,FOREGROUND_RED | 0x8);
getchar();
goto repeat1;
}
}
if(ch == '2')
{
filp = fopen(Path , "w+");
if(NULL == filp)
{
Print_Info_To_console("文件打开失败 \n",hOut,pos,0,20,FOREGROUND_RED | 0x8);
SetConsoleTextAttribute(hOut, FOREGROUND_RED | 0x8);
Print_Info_To_console("请按任意键重新选择输入 \n",hOut,pos,0,21,FOREGROUND_RED | 0x8);
getchar();
goto repeat1;
}
}
if(ch != '1' && ch != '2')
{
goto repeat1;
}
int i ;
for(i = 0 ; i < stucount ; i++)
{
fwrite(&(array[i]) , sizeof(struct student) , 1 , filp);
}
fclose(filp);
Print_Info_To_console("学生信息保存完毕\n",hOut,pos,0,20,FOREGROUND_GREEN | 0x8);
sleep(1) ;
}
//学生信息装载
void stu_load(HANDLE hOut)
{
int i ;
FILE *filp = NULL ;
char Path[30] ;
ClearScreen();
Print_Info_To_console("学生信息加载\n",hOut,pos,30,0,FOREGROUND_GREEN | 0x8);
Print_Info_To_console("请输入导入文件名 :\n",hOut,pos,0,1,FOREGROUND_GREEN | 0x8);
scanf("%s" , Path);
filp = fopen(Path , "r");
if(NULL == filp)
{
Print_Info_To_console("文件打开失败 \n",hOut,pos,0,20,FOREGROUND_RED | 0x8);
SetConsoleTextAttribute(hOut, FOREGROUND_RED | 0x8);
Print_Info_To_console("请按任意键退出 \n",hOut,pos,0,21,FOREGROUND_RED | 0x8);
fflush(stdin);
fflush(stdout);
getchar();
return ;
}
char buffer[1024] ;
char *p = NULL ;
int ret ;
while(1)
{
ret = fread(&(array[stucount]) , sizeof(struct student) , 1 , filp);
if(ret != 1)
break;
stucount++ ;
}
fclose(filp);
ClearScreen();
Print_Info_To_console("学生信息导入完毕\n",hOut,pos,0,20,FOREGROUND_GREEN | 0x8);
sleep(1);
}
//学生信息修改
void stu_modefi(HANDLE hOut)
{
int id ;
int flag = 0 ;
int location ;
char ch ;
replay:
ClearScreen();
Print_Info_To_console(" 学生信息修改\n",hOut,pos,30,0,FOREGROUND_GREEN | 0x8);
Print_Info_To_console("请输入学生ID: ",hOut,pos,0,1,FOREGROUND_GREEN | 0x8);
fflush(stdout);
scanf("%d" , &id);
int i ;
for(i = 0 ; i < stucount ; i++)
{
//如果ID匹配,也就是查找到这个学生的信息了
if(array[i].id == id)
{
flag = 1 ;
//保存当前数组的位置
location = i ;
break ;
}
}
//判断是否匹配成功的标志
if(flag == 1){
flag = 0 ;
//打印该学生的信息
ClearScreen();
Print_Info_To_console("找到该学生的信息如下:\n",hOut,pos,15,0,FOREGROUND_GREEN | 0x8);
SetConsoleTextAttribute(hOut, FOREGROUND_GREEN| 0x8);
pos.X = 0;
pos.Y = 1 ;
SetConsoleCursorPosition(hOut,pos);
printf("ID:%2d ",array[i].id);
SetConsoleTextAttribute(hOut, FOREGROUND_GREEN| 0x8);
pos.X = 0;
pos.Y = 2 ;
SetConsoleCursorPosition(hOut,pos);
printf("姓名:%s ",array[i].name);
SetConsoleTextAttribute(hOut, FOREGROUND_GREEN| 0x8);
pos.X = 0;
pos.Y = 3 ;
SetConsoleCursorPosition(hOut,pos);
printf("分数:%f ",array[i].score);
}
else
{
Print_Info_To_console("请入ID有误,请按任意键重新选择输入\n",hOut,pos,0,1,FOREGROUND_RED | 0x8);
fflush(stdin);
getchar();
goto replay ;
}
//询问是否需要修改
Print_Info_To_console("请问是否需要修改该学生的信息?按1确定,按2退回到主菜单\n",hOut,pos,0,4,FOREGROUND_GREEN | 0x8);
//刷新输出缓冲区
fflush(stdout);
//刷新输入缓冲区
fflush(stdin);
ch = getch();
ClearScreen();
if(ch == '1')
{
//是否需要修改学生的ID?
Print_Info_To_console("是否需要修改学生的ID?按1确定,按2不需要\n",hOut,pos,0,1,FOREGROUND_GREEN | 0x8);
fflush(stdout);
fflush(stdin);
ch = getch();
if(ch == '1')
{
ClearScreen();
Print_Info_To_console("修改学生ID为:",hOut,pos,0,1,FOREGROUND_GREEN | 0x8);
scanf("%d" , &(array[location].id));
Print_Info_To_console("修改学生ID成功,请按任意键返回主菜单\n",hOut,pos,0,2,FOREGROUND_GREEN | 0x8);
sleep(2);
fflush(stdin);
getchar();
return ;
}
if(ch == '2')
{
//是否需要修改学生的姓名
ClearScreen();
Print_Info_To_console("是否需要修改学生的姓名?按1确定,按2不需要\n",hOut,pos,0,1,FOREGROUND_GREEN | 0x8);
fflush(stdout);
fflush(stdin);
ch = getch();
if(ch == '1')
{
ClearScreen();
Print_Info_To_console("修改学生姓名为:",hOut,pos,0,1,FOREGROUND_GREEN | 0x8);
scanf("%s" , array[location].name);
Print_Info_To_console("修改学生姓名成功,请按任意键返回主菜单\n",hOut,pos,0,2,FOREGROUND_GREEN | 0x8);
sleep(1);
fflush(stdin);
getchar();
return ;
}
if(ch == '2')
{
//是否需要修改学生的成绩
ClearScreen();
Print_Info_To_console("是否需要修改学生的成绩?按1确定,按2不需要\n",hOut,pos,0,1,FOREGROUND_GREEN | 0x8);
fflush(stdout);
fflush(stdin);
ch = getch();
if(ch == '1')
{
ClearScreen();
Print_Info_To_console("修改学生成绩为:",hOut,pos,0,1,FOREGROUND_GREEN | 0x8);
scanf("%f" , &(array[location].score));
Print_Info_To_console("修改学生成绩成功,请按任意键返回主菜单\n",hOut,pos,0,2,FOREGROUND_GREEN | 0x8);
sleep(1);
fflush(stdin);
getchar();
return ;
}
if(ch == '2')
{
return ;
}
}
}
}
if(ch == '2')
{
Print_Info_To_console("请按任意键返回主菜单\n",hOut,pos,0,2,FOREGROUND_GREEN | 0x8);
fflush(stdin);
getchar();
return ;
}
}
//学生信息删除
void stu_delete(HANDLE hOut)
{
char ch ;
int id ;
char name[30] ;
repeat3:
ClearScreen();
Print_Info_To_console(" 学生信息删除\n",hOut,pos,30,0,FOREGROUND_GREEN | 0x8);
Print_Info_To_console(" 请选择按什么方式删除学生信息 :\n",hOut,pos,20,0,FOREGROUND_GREEN | 0x8);
Print_Info_To_console(" 1.ID",hOut,pos,10,1,FOREGROUND_GREEN | 0x8);
Print_Info_To_console(" 2.NAME\n",hOut,pos,10,2,FOREGROUND_GREEN | 0x8);
fflush(stdout);
ch = getch();
ClearScreen();
int i , j ;
if(ch == '1')
{
Print_Info_To_console("请输入ID:\n",hOut,pos,0,1,FOREGROUND_GREEN | 0x8);
scanf("%d" , &id);
getchar();
for(i = 0 ; i < stucount ; i++)
{
if(array[i].id == id)
{
SetConsoleTextAttribute(hOut, FOREGROUND_RED| 0x8);
printf("删除 : ID:%d NAME:%s score:%f\n" , array[i].id , array[i].name , array[i].score);
for(j = i ; j < stucount -1 ; j++)
array[j] = array[j+1] ;
stucount-- ;
break ;
}
}
}
if(ch == '2')
{
Print_Info_To_console("请输入NAME:\n",hOut,pos,0,1,FOREGROUND_GREEN | 0x8);
scanf("%s" , name);
getchar();
for(i = 0 ; i < stucount ; i++)
{
if(strcmp(array[i].name , name) == 0)
{
SetConsoleTextAttribute(hOut, FOREGROUND_RED| 0x8);
printf("删除 : ID:%d NAME:%s score:%f\n" , array[i].id , array[i].name , array[i].score);
for(j = i ; j < stucount -1 ; j++)
array[j] = array[j+1] ;
stucount-- ;
break ;
}
}
}
if(ch != '1' && ch != '2')
{
goto repeat3;
}
sleep(1);
}
重点看下最新的两个接口的更新演示过程:
学生信息修改演示:
学生信息删除演示:
下一篇: 用c语言写一个全面的学生管理系统变名