一次作业,学生离校情况管理系统,要求用链表和文件(整文件的时间占了八成QAQ)
首先想记录一下一个要命的细节。 没有加任何与文件有关的代码之前,窝突然想在Create()函数里加个是否连续输入的判断,但由于scanf的问题,出现了一系列玄幻结果:
·在打印“继续输入吗?继续请输入y或Y: ”之后,它为什么直接打印菜单???
·在显示菜单后输入y居然还能出现增添学生信息的提示词?!
原来是输入y后会有回车,进入判断是否继续输入的while循环,于是退出了Init()函数,回到主函数打印菜单,而主函数里也因为scanf的问题,缓存区里保留着上一步操作里输入的选择 “1” ,所以在输入y后(实际上输入任何“字符”效果都一样,原因同本段末所述)我们就进入了增加学生信息的Create()环节,所以解决方法就有了在scanf前清空缓存,还有就是,一开始进主函数要是输入的是 “字符”,会发现它一直打印Error!..进入谜之死循环...这还得归功于scanf, 要是计划输入%d,而接收的却不是数字的话,缓存区就一直存着上一次的数值,一直.... 但你要是输入 非1~6 的“数字”,它就会“如你所料”的只打印一次Error!后打印菜单让你重新选择。
于是乎就有了后面代码的改进:将scanf接收的整型改为字符型,并在其前清空缓存(在此万分感谢学长,救人一命啊~)
接下来再谈文件(对我来说真是要命QAQ)。每次运行程序都要通过Init()函数,“r"是只读,要是还没有”student.txt"文件则打开失败,以“w+"形式创建一个新的文件,要是上次已创建,则“r"方式打开成功(不出意外的话),%*s的作用是跳过(即接收但不处理)文件中的提示语(“学生姓名:” “学生学号:”等)而把其后的信息赋给q->name等,一个循环创建好链表,计算学生人数ct.——初始化完成,记得文件不用时要fclose(fp)一下 ( >_<)
最后在清空链表并退出前需要保存文件 ,也就是至关重要的write()函数了,先一个"w"方式,一开一关清空文件,再从头开始保存这次链表的内容,为什么要清空重写呢?干嘛不在新增的时候直接追加呢?一是为了保持学号从小到大的有序性(新插入的学生信息并不一定是以“追加”的形式挂在链表尾部啊),二是这样干挺省事的(bushi)。千万注意write()中fprintf里提示词与真实信息间的空格,因为%*s%s是以空格判断一条语句的。
(“w”模式:“只写”,若该文件存在则打开文件,并从头开始编辑,即原有内容会被删除;若该文件不存在则创建新文件)
#include
#include
#include
int ct;
typedef struct student{
char name[20],numb[20],data[20],traffic[20];
struct student* next;
}Node,*Link;
Link head=(Link)malloc(sizeof(Node));
void Init(Link h){ //打开文件,创建链表
Link p = h;
FILE *fp;
if(!(fp = fopen("student.txt","r"))) fp = fopen("student.txt","w+");
fscanf(fp,"%*s");
while(!feof(fp)){
Link q = (Link)malloc(sizeof(Node));
q->next = NULL;
fscanf(fp,"%s",q->name);
fscanf(fp, "%*s%s", q->numb);
fscanf(fp, "%*s%s", q->data);
fscanf(fp, "%*s%s", q->traffic);
fscanf(fp,"%*s");
p->next = q;
p = q;
ct++;
}
fclose(fp);
printf("文件打开或创建成功!\n");
}
void Create(){
char flag = 'y';
Link tail,pNew,p,q;
while((flag == 'y'||flag == 'Y')){
pNew=(Link)malloc(sizeof(Node));
printf("请输入学生姓名:");scanf("%s",pNew->name);
printf("学号:") ;scanf("%s",pNew->numb);
printf("离校日期:");scanf("%s",pNew->data);
printf("交通工具:");scanf("%s",pNew->traffic);
ct++;
if(ct==1){
head->next=pNew;
pNew->next=NULL;
}
else{
p=head,q=head->next;
while(q != NULL){
if(strcmp(pNew->numb,q->numb)<0)break; //插入时就使其有序,学号从小到大
p = q, q = q->next;
}
pNew->next=q;
p->next=pNew;
}
printf("继续输入吗?继续请输入y或Y:");
while((flag=getchar())!=EOF&&flag!='\n'); //清空缓存(因为scanf的问题...)
scanf("%c",&flag);
}
return;
}
void Delete(){
char cl[20];
int flag = 1;
printf("请输入要删除学生的学号:\n");
scanf("%s",cl);
Link p, q;
p=head,q=head->next;
while(q != NULL){
if(strcmp(q->numb, cl) == 0){
p->next = q->next;
q = q->next;
printf("删除成功!\n");
flag = 0, ct--;
}
else
p = q, q = q->next;
}
if(flag)printf("查无此学号!\n");
}
void PrintMenu(){
printf("*****************菜单*******************\n"
"*1.增加学生信息 2.删除学生信息 *\n"
"*3.修改学生信息 4.显示全部学生信息 *\n"
"*5.查询学生信息 6.保存并退出程序 *\n"
"****************************************\n"
);
printf("\nPlease enter number 1~6\n");
}
void Change(){
int c = 0, flag = 1;
char tp[20],modif[30];
printf("##注意## 学号不可修改!\n"
"选择:0.退出修改 1.修改姓名\n 2.修改离校日期 3.修改交通工具\n ");
printf("请输入您要修改的学生的学号:\n");
scanf("%s",tp);
Link p, q;
p = head, q = head->next;
while(q != NULL){
if(strcmp(q->numb, tp) == 0){
flag = 0;break;
}
else
p = q, q = q->next;
}
if(flag)printf("查无此号!\n");
else{
while(1){
printf("请选择序号(0~3):\n");
scanf("%d",&c);
if(!c)break;
switch(c){
case 1:printf("请输入替换内容(10字内):\n");scanf("%s",q->name);break;
case 2:printf("请输入替换内容(10字内):\n");scanf("%s",q->data);break;
case 3:printf("请输入替换内容(10字内):\n");scanf("%s",q->traffic);break;
default:printf("输入非法!\n");
}
printf("修改成功!\n");
}
}
}
void Display(){
Link tp;
int index = 1;
printf("\n-------The list has %d members------\n\n",ct);
tp = head->next;
while(tp != NULL){
printf("***The NO%d member:\n",index);
printf(" 姓名: %s\n 学号:%s\n 离校日期:%s\n 交通工具:%s\n",tp->name,tp->numb,tp->data,tp->traffic);
tp = tp->next;
index++;
}
}
void Find(){
Link p,q;
p = head, q = head->next;
char tp[20];
int flag = 1;
printf("请输入要查找到学生学号:\n");
scanf("%s",tp);
while(q != NULL){
if(strcmp(q->numb, tp) == 0){
printf("您要查找的学生信息如下:\n");
printf("姓名: %s\n学号:%s\n离校日期:%s\n交通工具:%s\n",q->name,q->numb,q->data,q->traffic);
flag = 0; break;
}
else
p = q, q = q->next;
}
if(flag) printf("未查找到!\n");
}
void write(){
Link q = head->next;
FILE *fp = fopen("student.txt","w");
fclose(fp);
while(q){
fp = fopen("student.txt","a+");
fprintf(fp, "学生姓名: %-10s 学生学号: %-10s 离校日期: %-10s 交通工具: %-10s", q->name, q->numb, q->data, q->traffic);
fprintf(fp,"\n");
q = q->next;
}
printf("保存成功!\n");
}
void Clear(){
write();
Link p;
while(head != NULL){
p = head;
head = head->next;
free(p);
}
free(head);
}
int main(){
char ch; //同样是为了解决scanf的问题,这里不用int, 用字符
Init(head);
while(1){
PrintMenu();
scanf("%c",&ch);
switch(ch){
case '1':Create(); break;
case '2':Delete(); break;
case '3':Change(); break;
case '4':Display(); break;
case '5':Find(); break;
case '6':Clear(); return 0;
default:printf("Error!\n");
}
while((ch=getchar())!=EOF&&ch!='\n'); //清空缓存
}
return 0;
}
结尾:这个短小的学生信息管理系统远比不上其他同学的“大作业”(人家还有模糊搜索...) ,但我希望它能对看到的小伙伴有所帮助(我为文件抓狂良久qwq) 这种只在头和尾增加有关文件的一小段代码,应该比较好接受,不用做太大修改。
希望大家看到错误能不吝指出,thanks! ~~ >_<