目录
First.main()
Second.Enter()
Third.Count()
Forth.Delete()
Fifth.Lookup()
Sixth.Modify()
Seventh.Append()
Eighth.Sort()
本人为大一学生,学C语言时间尚不长,所以本文的解释并不是十分的优美,代码略显臃肿;其次,本人使用的编译器为Visual Studio 2017,有些函数可能与您使用的会有出入(比如scanf与scanf_s,fopen与fopen_s),故请您对于本文仅作参考,希望本文对您有所帮助。
First.main()
首先,本管理系统分为8个函数部分,第一个main()函数部分如下:
#includestruct Student { int iNum; char cName[10]; int iScore; }student[10], student1[10]; void functions() { printf("t-------------------------------------------------------------------------------------------------n"); printf("t| Functions Menu |n"); printf("t| 1.Enter (录入) |n"); printf("t| 2.Delete(删除) |n"); printf("t| 3.Lookup(查询) |n"); printf("t| 4.Modify(更改) |n"); printf("t| 5.Append(添加) |n"); printf("t| 6.Sort(按成绩排序) |n"); printf("t| 7.Count(人数) |n"); printf("t-------------------------------------------------------------------------------------------------n"); } int main_n; int main() { char filename[20]; printf("please input the filename:n"); scanf_s("%s", filename, 20); while (1) { functions(); if (scanf_s("%d", &main_n) == 1) { if (main_n <1||main_n>7) return 0; switch (main_n) { case 1: Enter(filename); break; case 2: Delete(filename); break; case 3: Lookup(filename); break; case 4: Modify(filename); break; case 5: Append(filename); break; case 6: Sort(filename); break; case 7: Count(filename); break; } } else return 0; } return 0; }
注:第二行的D:\c.txt为我已经在D盘中建立的文本文件,在显示出菜单界面后,你只需按下相应功能前的数字即可
如果你输入的不是数字,又会发生什么呢?结果如下:
原因戳这里,或是这里
这是因为数据不对口,返回值不为1,有兴趣的小伙伴可以试一下%c、%lf等,看看输入不对称的值时scanf_s(scanf)的返回值是多少
Second.Enter()
接下来,编写第二个函数Enter(),可以看出其参量为一个字符指针filename,之后的几个函数也是以字符指针为参量:
#includeextern struct Student { int iNum; char cName[10]; int iScore; }student[10], student1[10]; void Enter(char *name) { int enter_n; FILE *fp; printf("How many students do you want to enter:n"); scanf_s("%d", &enter_n); printf("Ok!n"); errno_t err = fopen_s(&fp, name, "w+"); if (err != 0) { printf("error."); } for (int i = 0; i < enter_n; i++) { scanf_s("%d", &student[i].iNum); scanf_s("%s", student[i].cName, 10); scanf_s("%d", &student[i].iScore); } for (int i = 0; i < enter_n; i++) { fwrite(&student[i], sizeof(struct Student), 1, fp); } fclose(fp);//一次fopen对应一次fclose,中间只有一次fopen或一次fclose. err = fopen_s(&fp, name, "r+"); if (err != 0) { printf("error."); } for (int i = 0; i < enter_n; i++) { fread(&student1[i], sizeof(struct Student), 1, fp); } fclose(fp); }
注:这里要特别注意的一个前提就是fopen_s和fclose的配对使用,中间只能有一次对文本文件的读取或写入的 *** 作,刚开始编写这个函数时栽了好几个跟头,读者注意这一点
控制台输出如下:
Third.Count()
为了便于读者理解另外几个函数,我们先来介绍Count()函数,其代码如下:
#includeextern struct Student { int iNum; char cName[10]; int iScore; }student[10],student1[10]; int Count(char *filename) { FILE *fp; int count_n = 0; errno_t err = fopen_s(&fp, filename, "r+"); if (err != 0) { printf("error!"); return 0; } while(!feof(fp)) { if(fread(&student[count_n], sizeof(struct Student), 1, fp)==1) count_n++; } fclose(fp); printf("There are %d studentsn", count_n); return count_n; }
这个函数的功能主要是确定文件中学生的人数,先定义一个变量count_n,它的值初始化为0,以便每从文件中读取相应的字节数时它的值相应加1,获得正确的总人数。
这个函数的关键部分是:
while(!feof(fp)) { if(fread(&student[count_n], sizeof(struct Student), 1, fp)==1) count_n++; }
通过feof函数我们才得以实现这个功能,相关知识戳这里。
而为什么我编写这个函数时它的返回值时count_n呢?我明明可以return 0的啊。
这是因为我的本意是想将这个返回的值用作另外几个函数的参量,另外几个函数也会用到Count()函数的关键代码,这样就可以减少一些代码的重复量,但我并没有这样做是因为我想削弱这几个函数间的关联,让它们各司其职,增强它们的可移植性
Forth.Delete()
那么接下来就让我们继续了解第四个函数Delete(),先上代码:
#includeextern struct Student { int iNum; char cName[10]; int iScore; }student[10], student1[10]; int Delete(char *filename) { FILE *fp; int delete_n=0,delete_num=0; //delete_n用来保存要删除的数组元素下标,delete_num用来计算总的人数 errno_t err = fopen_s(&fp, filename, "r+"); if (err != 0) { printf("error."); } while (!feof(fp)) { if (fread(&student1[delete_num], sizeof(struct Student), 1, fp) == 1) delete_num++; } fclose(fp); for (int i = 0; i < delete_num; i++) { printf("%dt%st%dn", student1[i].iNum, student1[i].cName, student1[i].iScore); } printf("please input the number of the student you want to delete:n"); scanf_s("%d", &delete_n); if (delete_n < 0 || delete_n == 0||delete_n>delete_num) { printf("Sorry,I can't help!Cause you input the wrong number!n"); return 0; } for(int i=delete_n;i< delete_num;i++) { student1[i-1] = student1[i]; }//删除的不是对应学号的学生 err = fopen_s(&fp, filename, "w+"); if (err != 0) { printf("error."); } for (int i = 0; i < delete_num-1; i++) { fwrite(&student1[i], sizeof(struct Student), 1, fp); } fclose(fp); return 0; }
注:代码中已经说过,删除的不是对应学号的学生,这里再强调一遍!
执行后控制台中会一行行列出学生的信息,注意,你如果要删除某个同学的信息,直接输入它所在的行数即可
例如,如果我要删除上图中luog同学的信息,我只需输入2,可如果我输入了他的学号,控制台输出为
Fifth.Lookup()
第五个函数则是Lookup(),用来查询某个学生的信息,上代码:
#includeextern struct Student { int iNum; char cName[10]; int iScore; }student[10], student1[10]; int Lookup(char *filename) { FILE *fp; int lookup_n=0,lookup_num=0; //lookup_n用来计算有多少个学生,lookup_num用来储存要查询的学生学号 errno_t err = fopen_s(&fp, filename, "r+"); if (err != 0) { printf("error!"); } while (!feof(fp)) { if(fread(&student1[lookup_n],sizeof(struct Student),1,fp)==1) lookup_n++; } fclose(fp); for (int i = 0; i < lookup_n; i++) { printf("%dt%st%dn", student1[i].iNum, student1[i].cName, student1[i].iScore); } printf("please input the homologous number of the student:n"); scanf_s("%d", &lookup_num); for (int i = 0; i < lookup_n; i++) { if (student1[i].iNum== lookup_num) { printf("ttnumber name scoren"); printf("tt%*d%*s%*dn",6,student1[i].iNum,9, student1[i].cName,10, student1[i].iScore); return 0; } } if (lookup_num<0 || lookup_num>lookup_n) printf("Sorry,but I don't have the information of the student.n"); return 0; }
这个函数的大部分代码功能前文已经提到,小伙伴们主要的疑问可能是
printf("tt%*d%*s%*dn",6,student1[i].iNum,9, student1[i].cName,10, student1[i].iScore);
为什么会有%*d和%*s中的*呢?这个是为了让输出的代码对齐,如图
并且要注意,这里输入的是学号,不是行数,与Delete()函数刚好相反
Sixth.Modify()
接下来介绍Modify()函数,通过这个函数,我们只要输入对应的学生学号,即可修改对应学生的信息:
#includeextern struct Student { int iNum; char cName[10]; int iScore; }student[10], student1[10]; int Modify(char *filename) { FILE *fp; int modify_n=0, modify_num=0; int iTemp=0; //modify_n用来计算学生个数,modify_num用来保存要更改信息的学生的号码,iTemp用来保存对应学生的下标 errno_t err = fopen_s(&fp, filename, "r+"); if (err != 0) { printf("error!"); } while (!feof(fp)) { if (fread(&student1[modify_n], sizeof(struct Student), 1, fp) == 1) modify_n++; } fclose(fp); for (int i = 0; i < modify_n; i++) { printf("%dt%st%dn", student1[i].iNum, student1[i].cName, student1[i].iScore); } printf("please input the homologous number of the student:n"); scanf_s("%d", &modify_num); for (int i = 0; i < modify_n; i++) { if (student1[i].iNum == modify_num) iTemp = i; } if (iTemp == 0) { printf("Not have this student!n"); return 0; } printf("student%d.Num:", iTemp+1); scanf_s("%d", &student1[iTemp].iNum); printf("student%d.Name:", iTemp+1); scanf_s("%s", student1[iTemp].cName,sizeof(student1[iTemp].cName)); printf("student%d.Score:", iTemp+1); scanf_s("%d", &student1[iTemp].iScore); putchar('n'); err = fopen_s(&fp, filename, "w+"); if (err != 0) { printf("error!"); return 0; } for (int i = 0; i < modify_n; i++) { fwrite(&student1[i], sizeof(struct Student), 1, fp); } fclose(fp); return 0; }
控制台输出为:
在功能菜单下输入4后,控制台自动打印出已储存的学生信息,这时你只要对照学生信息输入对应的学号即可 。利用这个函数,你不仅可以行使修改功能,也可以全部修改达到替换目的。
细心的读者可以发现,本函数的一个变量modify_n、上一个函数的lookup_n、上上个函数的delete_num,以及接下来要讲解的Append()函数的append_n和Sort()函数的sort_n,与我上文说的那样,都与count_n行使着一样的功能,那就是计算人数。
Seventh.Append()
函数Append()有着与Enter()函数类似的功能,不同的是,Append()函数一次只能输入一个学生的信息,控制台输出如下:
在显示菜单后按5,会显示出“There are X students"的字样,接着会需要你输入新添加的学生的信息,它会自动连接上结构体数组的末尾,即连接上一位同学lu,样式如图:
Eighth.Sort()
接下来介绍最后一个函数Sort(),先上代码:
#include#include extern struct Student { int iNum; char cName[10]; int iScore; }student[10],student1[10]; int Sort(char *filename) { FILE *fp; int sort_n = 0; //sort_n用来计算学生个数 struct Student t; errno_t err = fopen_s(&fp, filename, "r+"); if (err != 0) { printf("error!"); return 0; } while (!feof(fp)) { if (fread(&student[sort_n], sizeof(struct Student), 1, fp)==1) sort_n++; } fclose(fp); err = fopen_s(&fp, filename, "w+"); if (err != 0) { printf("error!"); return 0; } for (int i = 0; i < sort_n; i++) { fwrite(&student[i], sizeof(struct Student), 1, fp); } fclose(fp); printf("I have order the array!n"); for (int i = 0; i < sort_n; i++) { printf("%dt%st%dn", student[i].iNum, student[i].cName, student[i].iScore); } return 0; }
用括起来的那四段代码,你可以随意选一段去掉后进行使用,这些排序均是按照学生的成绩进行排列的,如果要按照学号排列,只需将iScore改成iNum.
需要注意:
图右下角显示“不能将'struct Student'类型的值分配到'struct Student'类型的实体”,但实际上可以强制进行使用。
好了,本篇内容到此结束,愿对君有益。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)