C语言项目 :: 学生信息管理系统
前言:本期是C语言实战项目专栏的第一篇内容。此后,该专栏会不定期更新!
本篇基础需求:
- C 语言最基础语法;
- 要求对链表有一定基础了解;
- 能够使用C语言操作文件;
- 多文档编程。
=> 本期项目视频预览
目录
1. 文章内容说明
2. 设计分析
2.1 开发环境及配置
2.2 数据对象分析设计
2.3 数据存储分析设计
2.4 功能分析设计
3. 功能的设计实现
3.1 数据文件的设计实现
3.2 功能文件的设计实现
3.3 “插件”文件的设计实现
3.4 main函数文件
4. 结语
1. 文章内容说明
说明:本项目将会基于笔者的已有分享的文章内容进行续作,如需了解相关文章内容,直达链接:《无头链表的设计与实现》、《顺序栈与链式栈的设计与实现》。
2. 设计分析
该部分会简单叙述本项目到手到项目设计思路。
- 项目拆分:数据和功能;( + 环境基础)
- 数据对象分析:学生信息 + 成绩信息;(可合并)
- 功能分析:数据增删改查 + 辅助功能(菜单展示,数据存储与读取等);
- 界面展示:命令行模式。
2.1 开发环境及配置
本项目笔者的开发环境window10,编译器:vs2013。
2.2 数据对象分析设计
本项目的数据对象:学生成绩信息(其中包含学生基本信息和学科成绩信息)。
此处,笔者设定信息内容为:学号、姓名、班级、学科成绩(政治、英一、高数、专业课)
对应的数据数据类型:学号:int
姓名:char
班级:char
学科成绩:float(保留两位小数)
2.3 数据存储分析设计
学生信息管理存在增删改查,此时为了实现该功能需选取合适的数据结构对已有数据进行存储管理。
- 学生信息存储:使用链表: 结合数据添加,笔者设计使用链表,插入数据仅使用头插法,配合实现学生信息中的学号,若不指定输入,可自增记录,具体视情而定。
- 学生信息子数据使用结构体。
- 为了使程序结束数据不丢失,此处的练手项目使用文件存储!不使用数据库存储。
// 学生信息数据集结构体
typedef struct Student{
int stuNum;
char name[20];
char classroom[25];
float score_Politics;
float score_English;
float sroce_Math;
float sroce_Major;
}Stu;
// 结构体大小定义
#define SIZE_STU sizeof(struct Student)
// 链表结点
struct Node{
Stu data;
struct Node* next;
};
2.4 功能分析设计
此处仅叙述功能思路,具体实现需到实现部分。(且注意:本项目使用多文档编程)
关于 界面展示 :展示选项,展示输入需求,展示输出。必要的情况下实现返回界面模拟并设置延时效果。
关于 数据增删改查 :数据存储基于链表结构。增加数据直接使用头插法效率略高于尾插法。
关于 输出列表格式 :单独使用函数封装输出。
关于 文件存储预读取 :此处笔者设计封装成读取和保存的两个函数,且仅在程序启动时读取,程序结束时保存。
3. 功能的设计实现
本项目使用多文档编程。(本篇内容代码不含注释,需求注释移步【含注释版】或关注微信公众号:IT菜园,后台回复学生信息管理系统)划分:
数据文件:实现数据基础格式设计。
功能文件:实现全部的功能设计。
“插件文件”:实现某些必要的效果。
3.1 数据文件的设计实现
头文件:data.h
#pragma once
#include<stdio.h>
#include<stdlib.h>
#define FILENAME "STU.yf"
typedef struct Student{
int stuNum;
char name[20];
char classroom[25];
float score_Politics;
float score_English;
float score_Math;
float score_Major;
}Stu;
#define SIZE_STU sizeof(struct Student)
struct Node{
Stu data;
struct Node* next;
};
struct Node* initPointer();
struct Node* createNode(Stu* data);
void addPush(Stu* info);
void printStu();
void file2list();
void list2file();
void travel(struct Node* pHead);
文件:data.c
#include "data.h"
#include<string.h>
#include "tools.h"
extern struct Node* plist;
struct Node* initPointer(){
plist = NULL;
return plist;
}
struct Node* createNode(Stu* data){
struct Node* pnew = (struct Node*)malloc(sizeof(struct Node));
pnew->data.stuNum = data->stuNum;
strcpy(pnew->data.name, data->name);
strcpy(pnew->data.classroom, data->classroom);
pnew->data.score_Politics = data->score_Politics;
pnew->data.score_English = data->score_English;
pnew->data.score_Math = data->score_Math;
pnew->data.score_Major = data->score_Major;
pnew->next = NULL;
return pnew;
}
void addPush(Stu* info){
struct Node* pnew = createNode(info);
if (NULL == plist){
plist = pnew;
return;
}
else{
pnew->next = plist;
plist = pnew;
}
}
void file2list(){
FILE* fp = fopen(FILENAME, "rb");
if (NULL == fp){
printError("file2list", "文件不存在");
fp = fopen(FILENAME, "wb");
if (NULL == fp){
printError("file2list", "创建文件失败");
delay(5);
exit(-1);
}
fclose(fp);
return;
}
Stu temp;
int r;
while (1){
r = fread(&temp, 1, SIZE_STU, fp);
if (r < SIZE_STU){
break;
}
addPush(&temp);
}
fclose(fp);
}
void list2file(){
if (NULL == plist) return;
struct Node* ptemp = plist;
FILE* fp = fopen(FILENAME, "wb");
if (NULL == fp){
printError("list2file", "创建文件失败");
return;
}
while (ptemp){
fwrite(&(ptemp->data), 1, SIZE_STU, fp);
ptemp = ptemp->next;
}
fclose(fp);
}
3.2 功能文件的设计实现
头文件 func.h
#pragma once
void showMenu();
void stuAllInfoList();
void stuAllGrageList();
void stuInsertInfo();
void updateStuInfo();
void deleteStuInfo();
void coderInfo();
void outSystem();
struct Node* findInfo();
文件:func.c
#include "func.h"
#include "data.h"
#include<windows.h>
#include "tools.h"
extern struct Node* plist;
void showMenu()
{
system("cls");
printf("*****************************************************\n");
printf("**=============== 学生信息管理系统 ==============**\n");
printf("**--------------> 1. 学生信息列表 -----------**\n");
printf("**--------------> 2. 学生成绩列表 -----------**\n");
printf("**--------------> 3. 学生信息载入 -----------**\n");
printf("**--------------> 4. 学生信息修改 -----------**\n");
printf("**--------------> 5. 学生信息删除 -----------**\n");
printf("**--------------> 6. 查询学生信息 -----------**\n");
printf("**--------------> 7. 退出系统 -----------**\n");
printf("*****************************************************\n");
printf("\n\n");
int n;
printf("请输入编号进行选择:");
scanf("%d", &n);
switch (n)
{
case 1: stuAllInfoList(); break;
case 2: stuAllGrageList(); break;
case 3: stuInsertInfo(); break;
case 4: updateStuInfo(); break;
case 5: deleteStuInfo(); break;
case 6: findInfo(); break;
case 7:
list2file();
printf("感谢使用,再见!\n");
delay(3);
exit(1);
break;
case 8: travel(plist); break;
default:
break;
}
}
void stuAllInfoList()
{
struct Node* ptemp = plist;
printf("**=============== 学生基础信息列表 ==============**\n");
printf("学号\t姓名\t班级\n");
if (NULL == ptemp){
printf("暂无学生信息!\n");
printf("3秒后自动返回上层\n");
delay(3);
showMenu();
}
while (ptemp){
printf("%d\t%s\t%s\n",
ptemp->data.stuNum,
ptemp->data.name,
ptemp->data.classroom
);
ptemp = ptemp->next;
}
printf("\n\n展示完成!\n");
int n;
printf("输入任意值返回上层:");
scanf("%d", &n);
showMenu();
}
void stuInsertInfo()
{
Stu s = { 0 };
system("cls");
printf("\n");
printf("**=============== 学生信息载入 ==============**\n");
printf(" => 1. 增加学生信息\n");
printf(" => 2. 返回上层\n");
printf("\n");
printf("请输入编号进行选择:");
int n;
scanf("%d", &n);
if (2 == n)
{
showMenu();
}
else if (1 != n){
printf("指令输入错误!请重新输入!\n");
delay(3);
stuInsertInfo();
}
else{
// 2. 数据存入内存(链表)
printf("请输入学生学号:");
scanf("%d", &s.stuNum);
printf("请输入学生姓名:");
scanf("%s", s.name);
printf("请输入学生班级:");
scanf("%s", s.classroom);
printf("请输入学生政治成绩:");
scanf("%lf", &s.score_Politics);
printf("请输入学生英语成绩:");
scanf("%lf", &s.score_English);
printf("请输入学生高数成绩:");
scanf("%lf", &s.score_Math);
printf("请输入学生专业课成绩:");
scanf("%lf", &s.score_Major);
// 存入链表
addPush(&s);
printf("已有一条信息录入成功!\n");
list2file();
delay(3);
stuInsertInfo();
}
}
void travel(struct Node* pHead){
struct Node* ptemp = pHead;
if (NULL == ptemp)
{
printf("链表为空!\n");
return;
}
printf("plist:\n");
while (ptemp){
printf("%d\t%s\t%s\t%.2lf\t%.2lf\t%.2lf\t%.2lf\t\n",
ptemp->data.stuNum,
ptemp->data.name,
ptemp->data.classroom,
ptemp->data.score_Politics,
ptemp->data.score_English,
ptemp->data.score_Math,
ptemp->data.score_Major
);
ptemp = ptemp->next;
}
printf("\n");
delay(3);
showMenu();
}
void stuAllGrageList()
{
struct Node* ptemp = plist;
printf("**=============== 学生成绩列表 ==============**\n");
printf("学号\t姓名\t班级\t政治\t英一\t高数\t专业课\t\n");
if (NULL == ptemp){
printf("暂无学生信息!\n");
printf("3秒后自动返回上层\n");
delay(3);
showMenu();
}
while (ptemp){
printf("%d\t%s\t%s\t%.2lf\t%.2lf\t%.2lf\t%.2lf\t\n",
ptemp->data.stuNum,
ptemp->data.name,
ptemp->data.classroom,
ptemp->data.score_Politics,
ptemp->data.score_English,
ptemp->data.score_Math,
ptemp->data.score_Major
);
ptemp = ptemp->next;
}
printf("\n\n展示完成!\n");
int n;
printf("输入任意值返回上层:");
scanf("%d", &n);
showMenu();
}
struct Node* findInfo(){
printf("请输入学生姓名进行查询:");
const char* aimName = (const char*)malloc(20);
scanf("%s", aimName);
struct Node* ptemp = plist;
while (ptemp){
if (0 == strcmp(ptemp->data.name, aimName))
{
printf("找到了!信息如下!\n");
printf("%d\t%s\t%s\t%.2lf\t%.2lf\t%.2lf\t%.2lf\t\n",
ptemp->data.stuNum,
ptemp->data.name,
ptemp->data.classroom,
ptemp->data.score_Politics,
ptemp->data.score_English,
ptemp->data.score_Math,
ptemp->data.score_Major
);
free(aimName);
int n;
printf("输入任意值返回上层:");
scanf("%d", &n);
showMenu();
return ptemp;
}
ptemp = ptemp->next;
}
printf("查询失败!\n");
delay(3);
showMenu();
free(aimName);
return NULL;
}
struct Node* _findInfo(){
printf("请输入学生姓名进行查询:");
const char* aimName = (const char*)malloc(20);
scanf("%s", aimName);
struct Node* ptemp = plist;
while (ptemp){
if (0 == strcmp(ptemp->data.name, aimName))
{
printf("找到了!信息如下!\n");
printf("%d\t%s\t%s\t%.2lf\t%.2lf\t%.2lf\t%.2lf\t\n",
ptemp->data.stuNum,
ptemp->data.name,
ptemp->data.classroom,
ptemp->data.score_Politics,
ptemp->data.score_English,
ptemp->data.score_Math,
ptemp->data.score_Major
);
free(aimName);
return ptemp;
}
ptemp = ptemp->next;
}
printf("查询失败!\n");
delay(3);
showMenu();
free(aimName);
return NULL;
}
void deleteStuInfo(){
system("cls");
printf("------------管理系统---------------\n");
printf("====================删除学生信息====\n");
printf("1 - 通过名字删除学生\n");
printf("2 - 回到上层\n");
printf("请选择:");
int n;
scanf("%d", &n);
if (2 == n){
showMenu();
}
else if (1 != n){
printf("输入错误,请重新选择!\n");
delay(3);
deleteStuInfo();
}
struct Node* pDel = _findInfo();
struct Node* pPrev;
if (NULL == pDel){
printf("查无此人,删除学生失败!\n");
delay(3);
deleteStuInfo();
return;
}
if (pDel == plist){
plist = pDel->next;
free(pDel);
}
else{
pPrev = plist;
while (pPrev->next != pDel)
pPrev = pPrev->next;
pPrev->next = pDel->next;
free(pDel);
}
printf("删除学生成功!\n");
list2file();
delay(3);
showMenu();
}
void updateStuInfo(){
system("cls");
printf("获取功能源码 => 微信公众号:IT菜园\n");
delay(3);
showMenu();
}
3.3 “插件”文件的设计实现
该部分实现延时跳转和文件存储写入错误提醒。
头文件:tools.h
#pragma once
#include <stdio.h>
#include <windows.h>
//延时
void delay(int n);
//错误输出
void printError(char* functionName, char* errorInfo);
文件:tools.c
#include "tools.h"
void delay(int n){
for (int i = 0; i < n; i++){
printf(".");
Sleep(1000);
}
}
//错误输出
void printError(char* functionName, char* errorInfo){
printf("%s文件中%s函数第%d行出错:%s\n",
__FILE__, functionName, __LINE__, errorInfo);
delay(5);
}
3.4 main函数文件
#include<stdio.h>
#include "func.h"
#include "data.h"
// 声明全局指针
struct Node* plist;
int main()
{
// 初始化指针为空
plist = initPointer();
// 从文件中读取数据
file2list();
// 启动界面显示
showMenu();
while (1);
return 0;
}
4. 结语
含注释版代码获取地址:(待更新)