C++中FILE实操作---用C来实现【2】
C++中FILE实现操作---用C来实现
/*C来实现学生管理系统*/
/***********************************************************/
//该系统实现了那些操作
//1、菜单、增、删、改、查、打印、保存、载入
//2、检查是否已经存在的学号
//3、实现二级菜单 选择性修改等操作
//学到的知识点:
//1--绝对路径,指定盘符
//2--相对路径,不指定盘符,在执行文件的当前目录下
//3--void类型,即什么类型都能接受,double int char 等都可以传送
//4--刷新添加,每次写入将之前清零 保存写入现有的所有
//5--停止条件: 1】写入write停止条件: 内存中数据为0时候,有效数据的位置,即g_user[i].m_Num!=0
// 2】加载Load 停止条件: 文件中数据读取返回值为0,读取不到数据时,即int n=fread(&us, 1, sizeof(us), pf)=0
//6--fwrite : 两种模式 w 写入 清空原来写入
// a(append)追加,原来基础上写入
//?????????????????????????????//
//未解决问题:
//1、写入到txt文件中的数据有乱码
//2、项目多少有点不稳定,好像在选择修改地方
/***********************************************************/

1 #define _CRT_SECURE_NO_WARNINGS 2 #include<stdio.h> 3 #include<string.h> 4 #include<stdlib.h> 5 int i = 0; 6 struct SUser{//结构体 每个接头体保存三个数据 7 int m_Num; //学号数据 8 char m_Name[20]; //姓名数据 9 float m_Math; //成绩数据 10 11 }; 12 SUser g_user[10000] ;//可以实现保存10000条数据记录 13 void Print(){ 14 printf("\n==========================\n"); 15 printf("学号\t姓名\t成绩\n");//其中\t挺好用的 16 int i = 0,num=0; 17 while (g_user[i].m_Num){//0.1f只取一位 18 if (g_user[i].m_Num > 0){//将-1屏蔽 不打印 =0 停止退出循环 19 printf("%d\t%s\t%0.1f\n", g_user[i].m_Num, &g_user[i].m_Name, g_user[i].m_Math); 20 //这里注意,数组加引用就有问题了,数组第一个代表的是指针 21 //所以此处用g_user[i].m_Math 而不能用&g_user[i].m_Math 22 ++num; 23 } 24 ++i;//这里很重要,必须是先+后赋值 25 26 } 27 printf("当前共用: %d 条记录\n", num); 28 printf("==========================\n\n"); 29 } 30 void Save(){ 31 FILE *p; int i = 0; 32 p = fopen("学生管理系统.txt", "w"); 33 if (!p){ 34 puts("\n文件不存在/未保存文件!\n"); 35 return; 36 } 37 38 while (g_user[i].m_Num){//不为0时才存储,否则全部存储就浪费 39 if (-1 != g_user[i].m_Num){ //删除时候g_user[i].m_Num=-1 去掉这种情况 40 fwrite(&g_user[i], 1, sizeof(g_user[i]), p);//将什么,以什么样的方式写入哪里的文件 41 //每次写一块,总共写多少块 42 /*fprintf(p, "%d %s %f", &g_user[i]);*/ 43 } 44 ++i; 45 } 46 fclose(p); 47 } 48 void Load(){ 49 FILE *pf = fopen("学生管理系统.txt", "r"); 50 int i = 0,choose_key=0; 51 if (!pf){ 52 puts("文档中未保存数据,请重新录入"); 53 printf("\n 请选择:(1)继续 (2)退出"); 54 scanf_s("%d", &choose_key); 55 switch (choose_key){ 56 case 1: 57 return; 58 case 2: 59 return; 60 } 61 } 62 63 //SUser us;//定义一个结构体大小的结构体对象 创建临时结构体 传送到g_user 64 /*int n = fread(&g_user, 1, sizeof(us), pf);//读入方法一 65 while (n){ 66 ++i; 67 n = fread(&g_user[i], 1, sizeof(us), pf); 68 }*/ 69 //while (fread(&us, 1, sizeof(us), pf))//读入方法二 70 // g_user[i++] = us;//每次读入的数据放到g_user 71 while (fread(&g_user[i++], 1, sizeof(SUser), pf) > 0);//读入方法三 72 fclose(pf); 73 Print(); 74 } 75 void Add(){//增 76 //一共可以录入[10000]条数据,即为截止条件 77 int i = 0;//结构体中学号录入指针+1 78 int j = 0;//保持i的不动,即将g_user[i].m_Num作为被比较对象 79 int com_Num;//定义一个临时变量来检查是否有已存在的学号,输入时,将学号数据赋给该变量, 80 //然后再给g_user[i].m_Num,同所有g_user[i].m_Num中i之前数据比较 81 while (g_user[i].m_Num)//{//此处不能使g_user非零;应该是结构体中的某一个数据非零 82 //想想g_user结构体中的名字怎么可能=0? 83 i++;//先取值用,后++ 从0开始赋值 84 printf("请输入学号: "); 85 scanf_s("%d", &com_Num);//scanf_s("%s"不能添加其他的\n之类的 否则不现实 86 g_user[i].m_Num = com_Num; 87 j = i; 88 while (g_user[i].m_Num){//学号非空来检查是否重定义 89 --j; 90 if (g_user[j].m_Num == com_Num){ 91 printf("学号已存在,请重新是输入\n"); 92 printf("请输入学号: "); 93 scanf_s("%d", &com_Num); 94 j = i;//输入的数据还需要在检查一次 95 } 96 if (j < 0){ break; } 97 } 98 printf("请输入姓名: "); 99 scanf_s("%s", g_user[i].m_Name,sizeof(g_user[i].m_Name)); 100 //scanf_s("%s", g_user[i].m_Name) 直接这样,无法输入/崩溃 101 printf("请录入数学成绩: "); 102 scanf_s("%f", &g_user[i].m_Math); 103 Save(); 104 Print(); 105 } 106 void Delete(){//删 107 108 printf("\n请输入需要删除的学号序列号: "); 109 int i = 0; 110 int s_num = 0;//需要中间变量存储输入值,将和g_user[i].m_Num 111 int flag = 0;//设置标志位 作为判断是否找到被删除的序号 112 scanf_s("%d", &s_num); 113 while (g_user[i].m_Num){ 114 if (g_user[i].m_Num == s_num){ 115 g_user[i].m_Num = -1;//为什么不填0呢?填0代表结束了,后续的数据无法使用。 116 //-1只是代表不打,但不会结束跳出循环;0会结束,跳出循环 117 flag = 1; 118 break; 119 } 120 ++i;//往下找的同时,将s_num同g_user[i].m_Num对比; 121 } 122 if (flag == 0){//如果没找到需要删除的学号的序号 123 puts("\n\n 并未找到您所需要删除的学号 \n\n"); 124 return; 125 } 126 else{//找到了 127 Save(); 128 Print(); 129 } 130 } 131 void Modify(){//改 132 int i = 0,s_num=0,modify_i=0; 133 printf("\n请输入您需要修改的记录的学号: "); 134 scanf_s("%d", &s_num); 135 while (g_user[i].m_Num){//内容非空的情况下,进行学号数据的对比 136 if (g_user[i].m_Num == s_num){ 137 printf("\n\n (1)选择修改学号\n\n\n (2)选择修改姓名\n\n\n (3)选择修改成绩\n\n"); 138 printf("\n请选择需要修改的内容的选项: "); 139 scanf_s("%d", &modify_i); 140 do{ 141 switch (modify_i){ 142 case 1: 143 printf("请重新修改学号: "); 144 scanf_s("%d", &g_user[i].m_Num); 145 break; 146 case 2: 147 printf("请重新修改姓名: "); 148 scanf_s("%s", g_user[i].m_Name, sizeof(g_user[i].m_Name)); 149 break; 150 case 3: 151 printf("请重新修改成绩: "); 152 scanf_s("%f", &g_user[i].m_Math); 153 break; 154 } 155 printf("\n请问您还需要修改吗?继续,请上述序号;停止,选择按键0回车\n"); 156 printf("\n请选择: "); 157 scanf_s("%d", &modify_i); 158 } while (modify_i); 159 break; 160 } 161 ++i;//先增后赋值 162 } 163 if (!g_user[i].m_Num){//!g_user[i].m_Num即g_user[i].m_Num==0,即搜索到最后没有相同的内容 164 puts("\n未找到您需要修改记录的序号!"); 165 return; 166 } 167 Save(); 168 Print(); 169 } 170 void Find(){//查 171 int i = 0, s_num = 0; 172 printf("\n请输入需要查找的学号信息: "); 173 scanf_s("%d", &s_num); 174 while (g_user[i].m_Num){ 175 if (g_user[i].m_Num == s_num){ 176 printf("\n学号\t姓名\t成绩\n"); 177 printf("%d\t%s\t%0.1f\n", g_user[i].m_Num,g_user[i].m_Name,g_user[i].m_Math); 178 system("pause"); 179 break; 180 } 181 ++i; 182 } 183 if (!g_user[i].m_Num){ 184 puts("\n不存在您查找的内容\n"); 185 return; 186 } 187 } 188 int Menu(){//菜单 189 puts("1】浏览所有信息");//puts专门输出字符 190 puts("2】添加信息"); 191 puts("3】删除信息"); 192 puts("4】修改信息"); 193 puts("5】查找信息"); 194 puts("0】退出"); 195 printf("请选择: "); 196 int i = 0; 197 scanf_s("%d", &i); 198 switch (i){ 199 case 1: 200 Print(); 201 break; 202 case 2: 203 Add(); 204 break; 205 case 3: 206 Delete(); 207 break; 208 case 4: 209 Modify(); 210 case 5: 211 Find(); 212 } 213 return i; 214 } 215 216 int main(){ 217 Load(); 218 while (Menu()){//无限循环 219 220 }; 221 return 0; 222 }
实现编程,呈现控制台界面Load 已保存数据
内存中查看Save的数据,更加直观
说明】:1、上面两幅图的意思是一致对应的
2、上图是控制台画面,下面是保存数据的十六进制内存形式
3、红色方框下数据代表:学号;绿色横线共20个字节大小代表:姓名;黑色横线共4个字节数据代表:成绩;
最左侧手画粉红色:内存以16个字节递增
4、后期可以通过反编译,即更改内存中十六进制数据来实现控制台输出数据的变更。