C语言实现学生成绩管理
-
项目简介
用C语言的链表及文件操作实现学生成绩的管理,实现主要的添加、修改、删除、查询的主要功能,并在程序关闭时将数据存储在二进制的文件中并加密。下一次打开程序,先解密二进制文件,然后将数据读入内存,再允许用户的操作。
-
程序简示图
-
功能介绍
1. 加密数据:
程序结束时,现将生成的链表,写入二进制的临时文Temp.dat,再运用加密函数,将Temp.dat加密到文件Data.dat(就相当于数据库),并删除文件Temp.dat。程序开始运行时,先获取文件Data.dat的文件,并判断是数据,如果前两者之一的条件不满足则进入上图所示的添加数据并生成链表。如果获取到文件并且有数据,则解密到临时文件并将其读入到内存并生成链表。
2.加密算法:
加密算法采用简单XOR算法,也就是异或运算。利用了一个数与其自身相异或的到0,而与0异或也得到其本身。
1 如b为原文,a为加密后的密文,c代表密码,则 2 3 加密: 4 a=b^c; 5 6 解密 7 a^c=>b^c^c=>b
具体的该程序的加密,因为是对二进制文件加密,采用的是先将数据写入临时文件Temp.dat,再将其数据以一个一个字节读出加密,然后依次读入到文件Data.dat完成加密。
1 #define KEY 0x85 2 3 void secretFile(char *srcfile,char *dstfile){ 4 FILE *fp1,*fp2; 5 6 if((fp1=fopen(srcfile,"rb"))==NULL){ //获取被加密文件指针 7 return ; 8 } 9 10 if((fp2=fopen(dstfile,"wb"))==NULL){ //获取加密文件指针 11 return; 12 } 13 14 fseek(fp1,0,SEEK_END); 15 int length=ftell(fp1); //获取文件的长度 16 17 fseek(fp1,0,SEEK_SET); 18 19 char *p=(char *)malloc(sizeof(char)*length); 20 fread(p,sizeof(char),length,fp1);//将文件数据读入p所指内存空间 21 22 for(int i=0;i<length;i++){ 23 p[i]^=KEY; 24 } //异或加密 25 26 fwrite(p,sizeof(char),length,fp2);//将加密后的数据读入目标文件 27 28 fclose(fp1); 29 fclose(fp2); 30 }
调用加密函数
1 void jiemi(){ //解密 2 FILE *fp; 3 if((fp=fopen("Temp.dat","wb"))==NULL){ 4 return; 5 } //生成临时文件 6 fclose(fp); 7 secretFile("Data.dat","Temp.dat"); //解密到临时文件 8 } 9 10 11 void jiami(){ //加密 12 FILE *fp; 13 if((fp=fopen("Data.dat","wb"))==NULL){ 14 return; 15 } 16 fclose(fp); 17 secretFile("Temp.dat","Data.dat"); //加密到目标文件 18 remove("Temp.dat"); //删除临时文件 19 }
执行后的二进制文件用WinHEX查看:
加密前的文件:
加密后的文件:
在具体的代码为了安全,生成加密文件Data.dat会删除临时文件Temp.dat,更安全的应该是由用户输入KEY值加密,然后输入KEY解密,就相当于文件的密码。这里定义宏写入了KEY的值。
3.写入、读取文件
读取Temp.dat的文件生成链表,返回头指针
1 struct student *readData(){ 2 jiemi(); //调用解密,生成解密后的文件Temp.dat 3 4 struct student *head,*q,*p; 5 head=q=NULL; 6 int i=0; 7 FILE *fp; 8 if((fp=fopen("Temp.dat","rb"))==NULL){ 9 printf("打开文件 Temp.dat 失败\n"); 10 } 11 //获取文件指针 12 13 fseek(fp,0,SEEK_END); 14 int length=ftell(fp)/(sizeof(struct student)); 15 //获取文件长度,确定链表的长度 16 fseek(fp,0,SEEK_SET); 17 18 while(i<length){ 19 20 p=(struct student*)malloc(sizeof(struct student)); 21 22 fread(p,sizeof(struct student),1,fp); //读数据到p 23 24 if(head==NULL){ //生成头结点 25 head=q=p; 26 }else{ 27 q->next=p; //在尾节点添加数据 28 q=p; 29 } 30 i++; 31 } 32 q->next=NULL; //尾节点置为空 33 fclose(fp); 34 return head; 35 36 }
将内存中的链表存储到文件
1 void storeData(struct student *head){ 2 struct student *q; 3 FILE *fp; 4 if((fp=fopen("Temp.dat","wb"))==NULL){ 5 printf("打开文件 Temp.dat 失败\n"); 6 return; 7 } //获取文件指针 8 for(q=head;q!=NULL;q=q->next){ 9 10 fwrite(q,sizeof(struct student),1,fp); //将链表上的节点依次写入文件 11 } 12 fclose(fp); 13 printf("存储数据成功"); 14 }
具体代码:
头文件head.h:
1 #include<stdio.h> 2 #include<stdlib.h> 3 #include<string.h> 4 #include<malloc.h> 5 6 #define KEY 0x85 //定义加密字符串 7 8 struct student{ 9 char id[10]; //学号 10 char name[20]; //姓名 11 int math; //数学成绩 12 int english; //英语成绩 13 struct student *next; 14 }; //学生结构体 15 16 void secretFile(char *srcfile,char *dstfile);//加密函数 17 void jiemi(); //解密 18 void jiami(); //加密 19 bool isData(struct student *head,char tmp[]);//是否存在该节点 20 struct student* creatLink();//生成链表 21 struct student* findLink(struct student *head,char id[]);//查找节点 22 void infoDisplay(struct student *head);//查看所有节点信息 23 void chaxun(struct student *head);//查询学生信息 24 struct student* tianjia(struct student *head);//添加学生 25 struct student* deleteLink(struct student *head);//删除学生 26 struct student* xiugai(struct student *head);//修改学生信息 27 bool isFile(char filename[]);//判断是否存在文件 28 void storeData(struct student *head);//存储数据到文件 29 struct student *readData();//读入数据生成链表
33 void freeLink(struct sutdent *head);//释放链表
主函数main.cpp:
1 #include"head.h" 2 3 void menu(){ 4 struct student *head=NULL; 5 system("cls"); 6 if(false==isFile("Data.dat")){ 7 printf("第一次进入:请先添加数据:\n"); 8 head=creatLink(); 9 10 } else{ 11 head=readData(); 12 13 } 14 int iSelect=1; 15 while(iSelect!=6){ 16 system("cls"); 17 printf("请输入选项:\n"); 18 printf("1.查询成绩 2.添加成绩 3.删除成绩 4.修改成绩 5.数据一览 6.退出\n"); 19 scanf("%d",&iSelect); 20 switch(iSelect){ 21 case 1:chaxun(head);break; 22 case 3:head=deleteLink(head);break; 23 case 2:head=tianjia(head);break; 24 case 4:head=xiugai(head);break; 25 case 5:infoDisplay(head);break; 26 case 6:storeData(head);freeLink(head);jiami();system("pause");break; 27 default:printf("\n输入错误请重新输入:");system("pause");break; 28 } 29 } 30 } 31 32 33 int main(){ 34 menu(); 35 return 0; 36 }
具体函数function.cpp:
1 #include"head.h" 2 3 void freeLink(struct student *head){ 4 struct student *p,*q; 5 p=head; 6 while(p!=NULL){ 7 q=p; 8 p=p->next; 9 free(q); 10 } 11 } 12 13 14 void secretFile(char *srcfile,char *dstfile){ 15 FILE *fp1,*fp2; 16 if((fp1=fopen(srcfile,"rb"))==NULL){ 17 return ; 18 } 19 if((fp2=fopen(dstfile,"wb"))==NULL){ 20 return; 21 } 22 fseek(fp1,0,SEEK_END); 23 int length=ftell(fp1); 24 fseek(fp1,0,SEEK_SET); 25 char *p=(char *)malloc(sizeof(char)*length); 26 fread(p,sizeof(char),length,fp1); 27 for(int i=0;i<length;i++){ 28 p[i]^=KEY; 29 } 30 fwrite(p,sizeof(char),length,fp2); 31 fclose(fp1); 32 fclose(fp2); 33 } 34 35 36 void jiemi(){ 37 FILE *fp; 38 if((fp=fopen("Temp.dat","wb"))==NULL){ 39 return; 40 } 41 fclose(fp); 42 secretFile("Data.dat","Temp.dat"); 43 } 44 45 46 void jiami(){ 47 FILE *fp; 48 if((fp=fopen("Data.dat","wb"))==NULL){ 49 return; 50 } 51 fclose(fp); 52 secretFile("Temp.dat","Data.dat"); 53 remove("Temp.dat"); 54 } 55 56 57 bool isData(struct student *head,char tmp[]){ 58 struct student *q; 59 printf("flag\n"); 60 for(q=head;q!=NULL;q=q->next){ 61 if(strcmp(tmp,q->id)==0){ 62 return true; 63 } 64 } 65 66 return false; 67 } 68 69 //创建链表 70 struct student* creatLink(){ 71 struct student *head,*q,*p; 72 head=q=NULL; 73 char id[10]; 74 int i=0; 75 76 head=q=NULL; 77 while(1){ 78 printf("(#结束输入)\n请输入学号:"); 79 scanf("%s",id); 80 if(strcmp("#",id)==0){ 81 break; 82 } 83 p=(struct student*)malloc(sizeof(struct student)); 84 strcpy(p->id,id); 85 86 fflush(stdin); 87 printf("请输入姓名:"); 88 scanf("%s",p->name); 89 90 fflush(stdin); 91 printf("请输入数学成绩:"); 92 scanf("%d",&(p->math)); 93 94 fflush(stdin); 95 printf("请输入英语成绩:"); 96 scanf("%d",&(p->english)); 97 if(head==NULL){ 98 head=q=p; 99 q->next=NULL; 100 }else{ 101 if(isData(head,p->id)==true){ 102 printf("已经存在该学生,该次数据无效\n"); 103 } 104 else{ 105 q->next=p; 106 q=p; 107 q->next=NULL; 108 } 109 } 110 } 111 q->next=NULL; 112 return head; 113 } 114 115 116 117 118 119 120 struct student* findLink(struct student *head,char id[]){ 121 struct student *p; 122 for(p=head;p!=NULL;p=p->next){ 123 if(strcmp(id,p->id)==0)break; 124 } 125 if(p!=NULL){ 126 return p; 127 } 128 return NULL; 129 } 130 131 132 133 134 void infoDisplay(struct student *head){ 135 struct student *p; 136 system("cls"); 137 printf("学号\t姓名\t英语\t数学\n"); 138 for(p=head;p!=NULL;p=p->next){ 139 printf("%s\t%s\t%d\t%d\n",p->id,p->name,p->english,p->math); 140 } 141 system("pause"); 142 } 143 144 145 void chaxun(struct student *head){ 146 char temp[10]; 147 system("cls"); 148 fflush(stdin); 149 printf("请输入要查询学生的学号:"); 150 scanf("%s",temp); 151 struct student *p; 152 for(p=head;p!=NULL;p=p->next){ 153 if(strcmp(temp,p->id)==0)break; 154 } 155 if(p!=NULL){ 156 printf("学号\t姓名\t英语\t数学\n"); 157 printf("%s\t%s\t%d\t%d\n",p->id,p->name,p->english,p->math); 158 }else{ 159 printf("没有查到学生\n"); 160 } 161 system("pause"); 162 } 163 164 165 166 struct student* tianjia(struct student *head){ 167 struct student *add=(struct student*)malloc(sizeof(struct student)); 168 struct student *p=NULL,*q=NULL; 169 system("cls"); 170 fflush(stdin); 171 printf("请输入学号:"); 172 scanf("%s",add->id); 173 174 fflush(stdin); 175 printf("请输入姓名:"); 176 scanf("%s",add->name); 177 178 fflush(stdin); 179 printf("请输入英语成绩:"); 180 scanf("%d",&(add->english)); 181 182 fflush(stdin); 183 printf("请输入数学成绩:"); 184 scanf("%d",&(add->math)); 185 186 for(q=head;q!=NULL;q=q->next){ 187 if(strcmp(add->id,q->id)==0) 188 { 189 printf("已存在该学生,此次输入无效"); 190 break; 191 } 192 } 193 if(q==NULL){ 194 add->next=head; 195 head=add; 196 printf("添加数据成功\n"); 197 } 198 199 system("pause"); 200 return head; 201 } 202 203 204 205 //删除链表节点 206 struct student* deleteLink(struct student *head){ 207 struct student *p,*q; 208 char tmp[10]; 209 system("cls"); 210 211 fflush(stdin); 212 printf("请输入要删除学生的学号:\n"); 213 scanf("%s",tmp); 214 215 for(p=head,q=NULL;p!=NULL;q=p,p=p->next){ 216 if(strcmp(tmp,p->id)==0)break; 217 } 218 if(p!=NULL){ 219 if(q==NULL){ 220 head=p->next; 221 }else{ 222 q->next=p->next; 223 224 } free(p); 225 } 226 printf("删除成功"); 227 system("pause"); 228 return head; 229 } 230 231 232 struct student* xiugai(struct student *head){ 233 char tmp[10]; 234 struct student *q; 235 system("cls"); 236 237 fflush(stdin); 238 printf("请输入要修改学生的学号:"); 239 scanf("%s",tmp); 240 241 for(q=head;q!=NULL;q=q->next){ 242 if(strcmp(q->id,tmp)==0){ 243 break; 244 } 245 } 246 247 if(q==NULL){ 248 printf("修改失败,不存在该学生\n"); 249 }else{ 250 251 fflush(stdin); 252 printf("请输入姓名:"); 253 scanf("%s",q->name); 254 255 fflush(stdin); 256 printf("请输入英语成绩:"); 257 scanf("%d",&(q->english)); 258 259 fflush(stdin); 260 printf("请输入数学成绩:"); 261 scanf("%d",&(q->math)); 262 263 printf("修改成功\n"); 264 } 265 266 system("pause"); 267 return head; 268 } 269 bool isFile(char filename[]){ 270 FILE *fp; 271 if((fp=fopen(filename,"rb"))==NULL){ 272 273 return false; 274 } 275 fseek(fp,0,SEEK_END); 276 int length=ftell(fp)/(sizeof(struct student)); 277 if(length<1){ 278 return false; 279 } 280 fclose(fp); 281 return true; 282 } 283 284 285 286 void storeData(struct student *head){ 287 struct student *q; 288 FILE *fp; 289 if((fp=fopen("Temp.dat","wb"))==NULL){ 290 printf("打开文件 Temp.dat 失败\n"); 291 } 292 for(q=head;q!=NULL;q=q->next){ 293 294 fwrite(q,sizeof(struct student),1,fp); 295 } 296 297 298 fclose(fp); 299 printf("存储数据成功"); 300 } 301 302 struct student *readData(){ 303 jiemi(); 304 struct student *head,*q,*p; 305 head=q=NULL; 306 int i=0; 307 FILE *fp; 308 if((fp=fopen("Temp.dat","rb"))==NULL){ 309 printf("打开文件 Temp.dat 失败\n"); 310 }fseek(fp,0,SEEK_END); 311 int length=ftell(fp)/(sizeof(struct student)); 312 fseek(fp,0,SEEK_SET); 313 while(i<length){ 314 315 p=(struct student*)malloc(sizeof(struct student)); 316 317 fread(p,sizeof(struct student),1,fp); 318 319 if(head==NULL){ 320 head=q=p; 321 }else{ 322 q->next=p; 323 q=p; 324 } 325 i++; 326 } 327 q->next=NULL; 328 fclose(fp); 329 return head; 330 331 }
运行截图:
存在的不足:
该程序还存在许多不足,比如说很多出错处理没有处理,比如所要求输入整形时输入字符型,输入超过范围的处理等。程序在处理数据比较小的时候较好,但如果处理数据过大就不是很适用。界面比较简单。