本文主要介绍了将学生信息管理系统改造为文件存储版本…
主要涉及文件操作函数–将学生信息导入文件和从文件读取学生信息到程序中,从而达到数据持久化的效果
文章最后有源码展示
学生信息管理系统1.0静态版->学生信息管理系统2.0动态内存增长版->学生信息管理系统3.0文件存储版
一.文件存储版本的介绍
之前的博客中介绍用C实现了学生信息管理系统1.0静态版本和优化后的2.0动态版本.这两个版本都有一个弊端:两个版本对学生信息的操作都是在程序运行中存在的.而当程序结束后,其产生的有用的学生信息都会丢失…
而在学了C语言文件操作后,就可以实现将程序运行时产生的学生信息通过文件函数导入到本地文件中,而在下一次再次运行程序时可以从本地文件中读取之前保留的学生信息…能够实现数据的持久化,
而此篇博客就是将之前学生信息管理系统2.0版本改造为可文件存储的3.0版本
而前提要对文件的常用操作能够熟练运用 - - - 文件常用操作
二.学生信息管理系统文件版本3.0改造过程
改造主要设计 :增加三个菜单选项–将学生信息导入文件 和从文件里读取学生信息 以及增加和修改相关的函数
1.增加菜单选择选项
主要增加了三个选项 :清空现有学生信息 读取已有学生信息 保存当前学生信息
增加菜单选项前↓
增加菜单选项后↓
对应的枚举选项和增加分支 前↓
对应的枚举选项和增加分支 后↓
2.实现将学生信息导入文件
将学生信息导入到文件中使用的是fprintf 以文件形式格式化输出函数
void writestu(stumgt* pstus) // 往文件里写入学生信息
{
FILE* pf = fopen("学生信息.txt", "w");
if (pf == NULL)
{
printf("存储学生信息失败!!!\n");
return;
}
assert(pstus != NULL);
for (int i = 0; i < pstus->sz; i++) //从第一个学生记录到第sz-1个 即所有学生记录
{
fprintf(pf, "%s %s %s %d %s %s %s\n", pstus->stu[i].sno, pstus->stu[i].name, pstus->stu[i].sex, pstus->stu[i].age, pstus->stu[i].roomnum, pstus->stu[i].number, pstus->stu[i].add);
} //用fprintf函数按指定字符串格式输出每一个学生对应的信息输出到文件中 注意每个之间用空格分开 这样在读取的时候也会以空格形式作为分隔读取
printf("已保存当前已有学生信息\n");
fclose(pf);
}
具体实现思路为:
首先先以只读形式打开"学生信息.txt"文件,判断一下pf是否为空 来确认文件是否打开成功,
打开成功后用一个for循环从第一个学生信息开始直到当前学生信息最大有效个数往文件里写入信息,每次写入一个学生信息,
根据fprintf函数使用方法第一个是指向文件信息区的指针
第二个参数对应着学生信息结构体所有成员变量的格式输出形式 (注意:中间要用空格隔开成员信息每项属性…视觉上更对齐也能给读取学生信息时留下空格分隔符…)
而第三个参数对应着学生信息成员变量每个属性的输出项(注意除了年龄外其他的都是字符串形式 )
=========================================================
设计完后来测试下往文件里写入学生信息的效果:
先通过1选项添加三个测试用例↓
当选择10后最后可以看到程序已经成功打开一个"学生信息.txt"文件,并按照设计的格式向文件内部写入了三个学生信息↓
3.实现从文件中读取学生信息
从文件中读取学生信息的使用的是fscanf以文件形式格式化输入函数
void readstu(stumgt** pstus) //往程序内部读取学生信息
{
FILE* pf = fopen("学生信息.txt", "r");
if (pf == NULL)
{
printf("当前程序内没有存储学生信息...\n");
return;
}
else
{
assert(pstus != NULL);
if ((*pstus)->sz == ( * pstus)->capcity) //
{
addcapcity(pstus); //
printf("存储空间已满..增容中...\n"); //
Sleep(3000);
}
if ((*pstus)->sz ==( *pstus)->capcity) //
{
printf("容量已满,无法再添加学生信息\n");
fclose(pf);
return;
}
studata tmp = { 0 };
while (fscanf(pf, "%s%s%s%d%s%s%s", tmp.sno, tmp.name, tmp.sex, &tmp.age, tmp.roomnum, tmp.number, tmp.add) == 7)
{ //通过fscanf 以对应的格式往文件里读取字符串输入到指定的成员变量中
(* pstus)->stu[(*pstus)->sz] = tmp; //进入循环则表示已读取到信息 此时直接将tmp这个结构体变量信息传给 管理系统里的sz下标对应的学生信息
(*pstus)->sz++;
if ((*pstus)->sz == (*pstus)->capcity) //判断当前容量是否满
{
addcapcity(pstus); //
printf("存储空间不足..正在增容中...\n"); //
Sleep(3000);
}
if ((*pstus)->sz == (*pstus)->capcity) //
{
printf("容量已满,无法再添加学生信息\n");
fclose(pf);
return;
}
}
printf("已读取完成\n");
}
}
具体实现思路为:
1.先以只读形式打开"学生信息.txt"文件,判断pf是否为NULL来确认文件是否存在且已打开成功
2.打开成功后开始读取信息,首先判断当前学生管理系统容量是否足够,如果不够此时调用增容函数…
(注意此函数接受的是二级指针,调用增容函数传参也是二级指针,因为增容最后要改变main内部的存放指向学生信息动态空间的指针,通过二级指针可以得到其指针空间对指向的空间扩容或者无法扩容时会重新开辟一块新的空间将其地址给 学生信息结构体指针空间)
经过最后判断增容成功后进行读取学生信息…
3.fscanf第一个参数是指向文件信息区的指针,
第二个参数是对应读取的每个学生信息属性的格式输入字符
第三个参数对应的是输入格式符的输入项即将文件里的学生信息的每个属性输入到结构体成员的哪个属性变量中
(注意:除年龄外其他都是字符数组形式只需要得到数组名不需要取地址,而年龄是整形变量需要取地址)
4.通过fscanf读取数据返回值的特点:创建一个存放学生信息的临时结构体变量用while语句将其表达式里直接读取学生信息存放到临时结构体变量中
每读取成功一个学生信息会返回7 进入循环,将临时变量里的学生信息赋给学生信息结构变量然后有效学生信息个数sz++并判断一下容量是否已满增容
5.最后如果读取的学生信息返回值不为7则读取完了学生信息 出while循环此时文件里的学生信息已读取完成…
=========================================================
这里来测试一下从文件中读取学生信息的效果:
先打开之前保存的三个学生信息的文件,在最后一行再用键盘添加一组测试信息↓
此时测试选择9读取信息的效果↓
可以看到程序读取信息时空间不够自动扩容存储学生信息
此时选择显示学生信息看看效果↓:
发现此时存储在文件中的所有学生信息都被读取到了程序中…
4.实现清空现有学生信息
在使用学生信息管理系统过程中需要删除所有学生信息操作时,此时学生数量多使用删除操作一条条删除很满,此时增加一项清空所有学生信息功能
void emptystu(stumgt* pstus) //清空学生信息记录
{
assert(pstus != NULL);
pstus->sz = 0;
printf("学生信息已清空\n");
}
此功能实现很简单即将sz置为0即可
三.学生信息管理系统–3.0文件存储版源码展示
1.stu.h头文件
#pragma once
#include<stdio.h>
#include<string.h>
#include<assert.h>
#include<stdlib.h>
#include<windows.h>
#define SZ 3 //每次增加的容量个数
#define CAPCITY 3 //一开始设置的容量
typedef struct studentdata
{
char sno[20]; //学号
char name[20]; //名字
char sex[5]; //性别
int age; //年龄
char roomnum[20];// 寝室号
char number[12];// 电话号码
char add[50]; //地址
}studata;
typedef struct studentmanagement
{
int sz; //记录当前有效的学生信息个数
int capcity; //记录存放学生信息的最大容量
studata stu[]; //柔性数组 用于不确定数组元素个数 实现动态增长
}stumgt;
enum option //声明 枚举类型 option 对应的枚举常量为实现 管理系统 菜单功能的选项名称 枚举常量不能同名
{
EXIT, //退出
ADD, //添加
DROP, //删除
FIND, //查找
MODIFY, //修改
TOTAL, //统计
PRINT, //打印
SORT, //排序
EMPTY, //清空
READ, //读取
WRITE //写入
};
enum option1 // 修改菜单的选择项
{
END, //结束修改
MODALL, //修改整条信息
MODONE //修改某一项信息
};
enum option2 //修改单项的菜单选择项
{
RETURN, //返回上一层
MODSNO, //修改学号
MODNAME, //修改姓名
MODSEX, //修改性别
MODAGE, //修改年龄
MODROOM, //修改寝室号
MODNUMBER, //修改电话号码
MODADDRESS //修改地址
};
enum option3 //统计学生个数菜单 选择项
{
ENDCOUNT, //结束统计
COUNTALL, //统计所有学生信息
COUNTAGE, // 按年龄统计
COUNTROOM, //统计寝室号
COUNTSEX //按性别统计
};
void menu();
//void initstus(stumgt* pstus);
void addstu(stumgt** pstus);
void pritstus(stumgt* pstus);
void dropstu(stumgt* pstus);
void search(stumgt* pstus);
void modifystu(stumgt* pstus);
void countstu(stumgt* pstus);
void sortstu(stumgt* pstus);
void readstu(stumgt** pstus);
void writestu(stumgt* pstus);
void emptystu(stumgt* pstus);
2.stu.c源文件
#define _CRT_SECURE_NO_WARNINGS
#define _CRT_SECURE_NO_WARNINGS
#pragma warning(disable : 6031) //忽略返回值
#include"stu.h"
void menu()
{
printf(" 欢迎使用学生信息管理系统 \n");
printf("*************************************************\n");
printf("# 1.添加新的学生信息 2.删除指定学生信息 #\n");
printf("# 3.查找指定学生信息 4.修改指定学生信息 #\n");
printf("# 5.分类统计学生个数 6.显示所有学生信息 #\n");
printf("# 7.排序所有学生信息 8.清空现有学生信息 #\n");
printf("# 9.读取已有学生信息 10.保存当前学生信息 #\n");
printf("* 0.退出学生信息管理系统 *\n");
printf("*************************************************\n");
}
static void modifymenu1()
{
printf("*************************************************\n");
printf("# 1.修改整条学生信息 2.修改某项学生信息 #\n");
printf("# 0.退出修改菜单 #\n");
printf("*************************************************\n");
}
static void modifymenu2()
{
printf("*************************************************\n");
printf("# 1.修改学生学号 2.修改学生姓名 #\n");
printf("# 3.修改学生性别 4.修改学生年龄 #\n");
printf("# 5,修改学生寝室号 6.修改学生电话号码 #\n");
printf("# 7.修改学生家庭住址 0.返回上一步修改 #\n");
printf("*************************************************\n");
}
static void countmenu()
{
printf("*************************************************\n");
printf("# 1.统计所有学生个数 2.按年龄统计学生个数 #\n");
printf("# 3.按寝室号统计学生个数4.按性别统计学生个数 #\n");
printf("# 0.结束统计 #\n");
printf("*************************************************\n");
}
void initstus(stumgt* pstus)//初始化学生管理系统这个结果体变量
{
assert(pstus != NULL);
pstus->capcity = CAPCITY; // 初始化给capcity赋最大值
}
static void addcapcity(stumgt** pstus)
{
stumgt* tmp = (stumgt*)realloc(*pstus, sizeof(stumgt) + sizeof(studata) * ((*pstus)->capcity + SZ) ); //每次增容给原来空间扩大SZ个 存放学生信息空间
if (tmp == NULL) // 判断是否增容失败
{
perror("realloc");
return;
}
else
{
*pstus = tmp; // 将扩大的空间的地址 通过解引用传给 main函数stus这个指针变量
(*pstus)->capcity += SZ; //最大容量增容 SZ 个
}
}
static int is_repeat(stumgt* pstus, char tmp[]) //判断学号信息是否重复
{
int i = 0;
for (i = 0; i < pstus->sz; i++)
{
if (strcmp(tmp, pstus->stu[i].sno) == 0)
{
return 1;
}
}
return 0;
}
void addstu(stumgt** pstus)
{
assert(pstus != NULL);
if ((* pstus) ->sz == ( * pstus)->capcity) //判断当前是否容量满
{
addcapcity(pstus); //
printf("存储空间已满..增容中...\n"); //
Sleep(3000);
}
if (( * pstus)->sz == (*pstus)->capcity) //如果增容完容量还是满此时表示增容失败
{
printf("容量已满,无法再添加学生信息\n");
return;
}
else
{
system("cls"); //输入学生信息前清屏一次
printf("请输入学生学号:");
char tmp[20] = { 0 };
scanf("%s", tmp);
if (is_repeat((*pstus), tmp)) //学生学号为主要属性 应是唯一的且不能为空
{
printf("输入失败!!!已存在学号信息为%s的学生,不同学生信息不允许设置相同学号\n", tmp);
return;
}
strcpy((*pstus)->stu[(*pstus)->sz].sno, tmp); //不存在重复时将当前信息拷贝作为学生学号信息
printf("请输入学生名字:");
scanf("%s", (*pstus)->stu[(*pstus)->sz].name);
printf("请输入学生性别:");
scanf("%s", (*pstus)->stu[(*pstus)->sz].sex);
printf("请输入学生年龄:");
scanf("%d", &(*pstus)->stu[(*pstus)->sz].age); //注意年龄这里要&其他的都是地址
printf("请输入学生寝室号:");
scanf("%s", (*pstus)->stu[(*pstus)->sz].roomnum);
printf("请输入学生电话号码:");
scanf("%s", (*pstus)->stu[(*pstus)->sz].number);
printf("请输入学生家庭住址:");
scanf("%s", (*pstus)->stu[(*pstus)->sz].add);
(*pstus)->sz++;
system("cls");
printf("添加成功\n");
}
}
void pritstus(stumgt* pstus) //打印所有信息
{
assert(pstus != NULL);
system("cls"); //输出所有信息前先清屏一次
printf("%-10s\t%-10s\t%-5s\t%-10s\t%-10s\t%-12s\t%-20s\t\n", "学号", "姓名", "性别", "年龄", "寝室号", "电话号码", "家庭住址");//先设置好对应字段格式
int i = 0;
for (i = 0; i < pstus->sz; i++)
{
printf("%-10s\t%-10s\t%-5s\t%-10d\t%-10s\t%-12s\t%-20s\t\n", //按设置好的格式对其打印数据
pstus->stu[i].sno,
pstus->stu[i].name,
pstus->stu[i].sex,
pstus->stu[i].age,
pstus->stu[i].roomnum,
pstus->stu[i].number,
pstus->stu[i].add);
}
}
static int findstu(stumgt* pstus, char tmp[]) //封装的内部 查找学生学号信息的函数 找到返回对应的数组元素下标 没找到返回-1
{
assert(pstus != NULL);
int i = 0;
for (i = 0; i < pstus->sz; i++)
{
if (strcmp(tmp, pstus->stu[i].sno) == 0)
return i;
}
return -1;
}
void dropstu(stumgt* pstus) //删除学生信息
{
assert(pstus != NULL);
if (pstus->sz == 0) //判断学生记录是否为空
{
printf("当前没有学生信息,无法删除\n");
return;
}
char tmp[20] = { 0 };
printf("输入要删除的学生的学号信息:");
scanf("%s", tmp);
int num = findstu(pstus, tmp); //使用内部封装的查找函数
if (num == -1)
{
printf("没有找到要删除的学生信息\n");
return;
}
else
{
int i = 0;
for (i = num + 1; i < pstus->sz; i++)
{
pstus->stu[i - 1] = pstus->stu[i];
}
pstus->sz--;
printf("已删除学号为%s的学生成员\n", tmp);
}
}
void search(stumgt* pstus) //查找学生信息的函数 以名字作为查找标准
{
assert(pstus != NULL);
char tmp[20] = { 0 };
printf("请输入要查找的学生姓名:");
scanf("%s", tmp);
system("cls");
printf("已查询到以下姓名为%s的学生信息↓↓↓\n", tmp); //找到后按设置的对齐格式输出查找的信息
printf("%-10s\t%-10s\t%-5s\t%-10s\t%-10s\t%-12s\t%-20s\t\n", "学号", "姓名", "性别", "年龄", "寝室号", "电话号码", "家庭住址");
int i = 0;
for (i = 0; i < pstus->sz; i++)
{
if (strcmp(tmp, pstus->stu[i].name) == 0)
{
printf("%-10s\t%-10s\t%-5s\t%-10d\t%-10s\t%-12s\t%-20s\t\n",
pstus->stu[i].sno,
pstus->stu[i].name,
pstus->stu[i].sex,
pstus->stu[i].age,
pstus->stu[i].roomnum,
pstus->stu[i].number,
pstus->stu[i].add);
}
}
}
static void modifyall(stumgt* pstus) //内部封装的修改整条学生信息的函数
{
char tmp[20] = { 0 };
printf("请输入要修改的学生学号信息:");
scanf("%s", tmp);
int num = findstu(pstus, tmp); //先判断是否存在要修改的学生信息
if (num == -1)
{
printf("未找到要修改的学生信息\n");
return;
}
else
{
system("cls"); //输入学生信息前清屏一次
printf("请输入学生学号:");
char tmp[20] = { 0 };
scanf("%s", tmp);
if (is_repeat(pstus, tmp)) //学生学号为主要属性 应是唯一的且不能为空
{
printf("输入失败!!!已存在学号信息为%s的学生,不同学生信息不允许设置相同学号\n", tmp);
return;
}
strcpy(pstus->stu[num].sno, tmp); //修改后的学号在之前学生信息里没有重复的则将tmp的拷贝修改当前学生信息学号
printf("请输入学生名字:");
scanf("%s", pstus->stu[num].name);
printf("请输入学生性别:");
scanf("%s", pstus->stu[num].sex);
printf("请输入学生年龄:");
scanf("%d", &pstus->stu[num].age);
printf("请输入学生寝室号:");
scanf("%s", pstus->stu[num].roomnum);
printf("请输入学生电话号码:");
scanf("%s", pstus->stu[num].number);
printf("请输入学生家庭住址:");
scanf("%s", pstus->stu[num].add);
printf("修改成功\n");
}
}
static void modifysno(stumgt* pstus, int num) //内部封装的单独修改学号的函数
{
printf("你要将学号修改为:");
char tmp[20] = { 0 };
scanf("%s", tmp);
if (is_repeat(pstus, tmp))
{
printf("修改失败,不能输入已有的学号\n");
return;
}
else
{
strcpy(pstus->stu[num].sno, tmp);
printf("修改成功\n");
}
}
static void modifyname(stumgt* pstus, int num)//内部封装的单独修改名字的函数
{
printf("你要将名字修改为:");
scanf("%s", pstus->stu[num].name);
printf("修改成功\n");
}
static void modifysex(stumgt* pstus, int num)//内部封装的单独修改性别的函数
{
printf("你要将性别修改为:");
scanf("%s", pstus->stu[num].sex);
printf("修改成功\n");
}
static void modifyage(stumgt* pstus, int num)//内部封装的单独修改年龄的函数
{
printf("你要将年龄修改为:");
scanf("%d", &pstus->stu[num].age);
printf("修改成功\n");
}
static void modifyroomnum(stumgt* pstus, int num)//内部封装的单独修改寝室号的函数
{
printf("你要将寝室号修改为:");
scanf("%s", pstus->stu[num].roomnum);
printf("修改成功\n");
}
static void modifynumber(stumgt* pstus, int num)//内部封装的单独修改电话号码的函数
{
printf("你要将电话号码修改为:");
scanf("%s", pstus->stu[num].number);
printf("修改成功\n");
}
static void modifyadd(stumgt* pstus, int num)//内部封装的单独修改地址的函数
{
printf("你要将地址修改为:");
scanf("%s", pstus->stu[num].add);
printf("修改成功\n");
}
static void modifyone(stumgt* pstus) //内部封装修改整条学生信息里的某项信息函数
{
char tmp[20] = { 0 };
printf("请输入要修改的学生学号信息:");
scanf("%s", tmp);
int num = findstu(pstus, tmp); //先判断是否存在该学生信息
if (num == -1)
{
printf("未找到要修改的学生信息\n");
return;
}
else
{
int input = 0;
modifymenu2(); //下面为函数指针数组将一个0和上面7个封装好的修改对应学生信息的函数指针作为数组初始化信息(0是为了方便下标对其选项)
void(*mod[8])(stumgt*, int) = { 0,modifysno,modifyname,modifysex,modifyage,modifyroomnum,modifynumber,modifyadd };
printf("请选择修改的内容:");
do
{
scanf("%d", &input);
if (input >= 8 || input < 0)
{
printf("非法输入,请重新选择\n");
}
else if (input == 0)
{
printf("退回上一层修改菜单\n");
}
else
mod[input](pstus, num); //根据菜单对应input输入的值调用 数组里相对应的函数指针
} while (input >= 8 || input < 0); //超出重新输入
}
}
void modifystu(stumgt* pstus) //修改学生信息的函数
{
int input = 0;
do
{
modifymenu1();
printf("请选择:");
scanf("%d", &input);
switch (input)//选择修改整条学生信息还是修改一条里某一项的学生信息
{
case 1:
modifyall(pstus);
break;
case 2:
modifyone(pstus);
break;
case 0:
printf("已结束修改操作\n");
break;
default:
printf("非法输入,请重新输入\n");
}
} while (input);
}
static void countall(stumgt* pstus) //内部封装的统计当前所有学生信息记录函数
{
printf("已统计当前系统中有%d个学生\n", pstus->sz);
return;
}
static void countage(stumgt* pstus) //统计年龄范围内学生记录的个数
{
int age1 = 0;
int age2 = 0;
int age = 0;
printf("请输入两个数字将统计其范围内的年龄个数(如果两个数字相同则统计这个数字年龄的学生个数)");
scanf("%d%d", &age1, &age2);
int count = 0;
int i = 0;
for (i = 0; i < pstus->sz; i++)
{
age = pstus->stu[i].age;
if (age >= age1 && age <= age2)
{
count++;
}
}
printf("在%d岁和%d岁之间的学生个数为%d\n", age1, age2, count);
return;
}
static void countroom(stumgt* pstus) //统计 寝室号的个数
{
char room[20] = { 0 };
printf("请输入寝室号:");
scanf("%s", room);
int i = 0;
int count = 0;
for (i = 0; i < pstus->sz; i++)
{
if (strcmp(room, pstus->stu[i].roomnum) == 0)
{
count++;
}
}
printf("寝室号为%s的寝室个数为%d个\n", room, count);
return;
}
static countsex(stumgt* pstus) //统计相同性别的学生个数
{
char sex[5] = { 0 };
printf("请输入要统计的性别:");
scanf("%s", sex);
int i = 0;
int count = 0;
for (i = 0; i < pstus->sz; i++)
{
if (strcmp(sex, pstus->stu[i].sex) == 0)
{
count++;
}
}
printf("性别为%s的学生个数为:%d\n", sex, count);
}
void countstu(stumgt* pstus) //统计学生信息的函数
{
assert(pstus != NULL);
system("cls");
int input = 0;
do
{
countmenu();
printf("请选择统计方式:");
scanf("%d", &input);
switch (input) //对应菜单输入input选择 跳转到上面封装的统计函数
{
case COUNTALL:
countall(pstus);
break;
case COUNTAGE:
countage(pstus);
break;
case COUNTROOM:
countroom(pstus);
break;
case COUNTSEX:
countsex(pstus);
break;
case ENDCOUNT:
printf("已结束统计\n");
break;
default:
printf("非法输入,请重新选择\n");
}
} while (input);
}
int cmp_sno(const studata stu1, const studata stu2) // 为qsort 函数设置的函数指针 用于比较两个元素的大小传给qsort
{
return strcmp(stu1.sno, stu2.sno); //比较两个学生里的学号大小 进行排序 这两个学生元素
}
void sortstu(stumgt* pstus) // 升序排序所有学生记录的函数
{
if (pstus->sz == 0) //判断排序时是否为空
{
printf("当前学生记录为空,无法排序\n");
return;
}
qsort(pstus->stu, pstus->sz, sizeof(studata), cmp_sno); //
printf("已按学号完成升序排序\n");
}
void readstu(stumgt** pstus) //往程序内部读取学生信息
{
FILE* pf = fopen("学生信息.txt", "r");
if (pf == NULL)
{
printf("当前程序内没有存储学生信息...\n");
return;
}
else
{
assert(pstus != NULL);
if ((*pstus)->sz == ( * pstus)->capcity) //
{
addcapcity(pstus); //
printf("存储空间已满..增容中...\n"); //
Sleep(3000);
}
if ((*pstus)->sz ==( *pstus)->capcity) //
{
printf("容量已满,无法再添加学生信息\n");
fclose(pf);
return;
}
studata tmp = { 0 };
while (fscanf(pf, "%s%s%s%d%s%s%s", tmp.sno, tmp.name, tmp.sex, &tmp.age, tmp.roomnum, tmp.number, tmp.add) == 7)
{ //通过fscanf 以对应的格式往文件里读取字符串输入到指定的成员变量中
(* pstus)->stu[(*pstus)->sz] = tmp; //进入循环则表示已读取到信息 此时直接将tmp这个结构体变量信息传给 管理系统里的sz下标对应的学生信息
(*pstus)->sz++;
if ((*pstus)->sz == (*pstus)->capcity) //判断当前容量是否满
{
addcapcity(pstus); //
printf("存储空间不足..正在增容中...\n"); //
Sleep(3000);
}
if ((*pstus)->sz == (*pstus)->capcity) //
{
printf("容量已满,无法再添加学生信息\n");
fclose(pf);
return;
}
}
printf("已读取完成\n");
}
}
void writestu(stumgt* pstus) // 往文件里写入学生信息
{
FILE* pf = fopen("学生信息.txt", "w");
if (pf == NULL)
{
printf("存储学生信息失败!!!\n");
return;
}
assert(pstus != NULL);
for (int i = 0; i < pstus->sz; i++) //从第一个学生记录到第sz-1个 即所有学生记录
{
fprintf(pf, "%s %s %s %d %s %s %s\n", pstus->stu[i].sno, pstus->stu[i].name, pstus->stu[i].sex, pstus->stu[i].age, pstus->stu[i].roomnum, pstus->stu[i].number, pstus->stu[i].add);
} //用fprintf函数按指定字符串格式输出每一个学生对应的信息输出到文件中 注意每个之间用空格分开 这样在读取的时候也会以空格形式作为分隔读取
printf("已保存当前已有学生信息\n");
fclose(pf);
}
void emptystu(stumgt* pstus) //清空学生信息记录
{
assert(pstus != NULL);
pstus->sz = 0;
printf("学生信息已清空\n");
}
3.text.c源文件
#define _CRT_SECURE_NO_WARNINGS
#define _CRT_SECURE_NO_WARNINGS
#pragma warning(disable : 6031)
#include"stu.h"
int main()
{
stumgt* stus = (stumgt*)calloc(1, sizeof(stumgt) + sizeof(studata) * CAPCITY);//在堆区创建stumgt类型大小的空间给柔性数组分配的空间
int i = 0;
initstus(stus);
do
{
menu();
printf("请选择:");
scanf("%d", &i);
switch (i)
{
case ADD:
addstu(&stus); //因为要动态增容 stus内的指针可能改变 ,这里用二级指针传址调用
break;
case DROP:
dropstu(stus);
break;
case FIND:
search(stus);
break;
case MODIFY:
modifystu(stus);
break;
case TOTAL:
countstu(stus);
break;
case PRINT:
pritstus(stus);
break;
case SORT:
sortstu(stus);
break;
case EXIT:
printf("已退出学生信息管理系统\n");
break;
case READ:
readstu(&stus);
break;
case WRITE:
writestu(stus);
break;
case EMPTY:
emptystu(stus);
break;
default:
printf("选择错误,请重新输入\n");
break;
}
} while (i);
return 0;
}
四.总结
学生信息管理系统三个版本已经全部写完, 而实现此系统也将学到的知识基本都串联了起来,
尽管写代码过程中构思时间久,写完寻找bug解决bug所花时间多.但是这都是让自己知识更牢固的一个过程,
学习本就是一个不断打磨的过程,愿每个人能坚持自己的目标,在每个阶段都能看到不一样的自己…文章来源:https://www.toymoban.com/news/detail-807894.html
文章来源地址https://www.toymoban.com/news/detail-807894.html
到了这里,关于赶紧进来看看---C语言实现学生信息管理系统(3.0文件存储版)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!