为什么用fwrite写入文件中,关闭程序重新打开读这个文件会不行
要写一个学生成绩管理系统,第一次运行没有问题,但第二次我想直接从上次登记的数据读取的时候就不行了。有没有大佬帮忙解答一下
#include <stdio.h>
#include <malloc.h>
#define LEN sizeof(struct student)
struct student
{
int num;
char name;
int score;
struct student *next;
};
int n;//统计学生人数
int main()
{
struct student *creat();
struct student *insert(struct student *head,struct student *stud);
struct student *del(struct student *head ,int num);
void print(struct student *head);
void search(struct student *head,int num);
void chucun(struct student *head);
void daochu(struct student *head); //函数声明
struct student *head,*stu;
int del_num,ser_num,i;
printf("\n\t学生管理系统1.0\n\n");
printf("--------------菜单--------------\n\n");
printf("\t1.登记学生信息\n");
printf("\t2.删除学生信息\n");
printf("\t3.增加学生信息\n");
printf("\t4.查找学生信息\n");
printf("\t5.浏览学生信息\n");
printf("\t6.储存到文件\n");
printf("\t7.从文件导出\n");
printf("\t8.退出系统\n");
printf("\n说明:学生信息输入0,表示输入结束\n\n");
printf("请选择:");
scanf("%d",&i);
while(i!=8)
{
switch(i)
{
case 1: head=creat();break;
case 2:
{
printf("请输入要删除的学号:");
scanf("%d",&del_num);
while(del_num!=0)
{
head=del(head,del_num);
printf("请输入要删除的学号:");
scanf("%d",&del_num);
}
break;
}
case 3:
{
printf("请输入要增加的学生的信息\n");
printf("请输入学号,姓名(用逗号隔开):");
stu=(struct student *)malloc(LEN);
scanf("%d,%s",&stu->num,&stu->name);
printf("请输入分数:");
scanf("%d",&stu->score);
while(stu->num!=0)
{
head=insert(head,stu);
printf("请输入要增加的学生的信息\n");
printf("请输入学号,姓名(用逗号隔开):");
stu=(struct student *)malloc(LEN);
scanf("%d,%s",&stu->num,&stu->name);
printf("请输入分数:");
scanf("%d",&stu->score);
}
break;
}
case 4:
{
printf("请输入要查找学生的学号:");
scanf("%d",&ser_num);
search(head,ser_num);
break;
}
case 5: print(head);break;
case 6: chucun(head);break;
case 7: daochu(head);break;
case 8: break;
default : printf("请输入1-8之间的数字!!!\n");
}
printf("\n\t学生管理系统1.0\n\n");
printf("--------------菜单--------------\n\n");
printf("\t1.登记学生信息\n");
printf("\t2.删除学生信息\n");
printf("\t3.增加学生信息\n");
printf("\t4.查找学生信息\n");
printf("\t5.浏览学生信息\n");
printf("\t6.储存到文件\n");
printf("\t7.从文件导出\n");
printf("\t8.退出系统\n");
printf("\n说明:学生信息输入0,表示输入结束\n\n");
printf("请选择:");
scanf("%d",&i);
}
return 0;
}
struct student *creat() //建立链表的函数
{
struct student *head,*p1,*p2;
n=0;
p1=p2=(struct student *)malloc(LEN);
printf("请输入学号,姓名(用逗号隔开):");
scanf("%d,%s",&p1->num,&p1->name);
printf("请输入分数:");
scanf("%d",&p1->score);
head=NULL;
while(p1->num!=0)
{
n=n+1;
if(n==1) head=p1;
else p2->next=p1;
p2=p1;
p1=(struct student *)malloc(LEN);
printf("请输入学号,姓名(用逗号隔开):");
scanf("%d,%s",&p1->num,&p1->name);
printf("请输入分数:");
scanf("%d",&p1->score);
}
p2->next=NULL;
return head;
}
struct student *insert(struct student *head,struct student *stud)//插入结点的函数
{
struct student *p0,*p1,*p2;
p1=head;
p0=stud; //指向要插入的结点
if(head==NULL) //如果为空链表
{
head=p0;
p0->next=NULL;
}
else
{
while((p0->num>p1->num)&&(p1->next!=NULL))
{
p2=p1;
p1=p1->next;
}
}
if(p0->num<=p1->num)
{
if(head==p1) head=p0;//插入的是头结点
else p2->next=p0; //插入的是中间结点
p0->next=p1;
}
else //插入的是尾结点
{
p1->next=p0;
p0->next=NULL;
}
n=n+1;
return(head);
}
struct student *del(struct student *head ,int num)//删除结点的函数
{
struct student *p1,*p2;
if(head==NULL)
{
printf("\n该表是空表!\n");
return(head);
}
p1=head;
while(num!=p1->num&&p1->next!=NULL)//p1指向的不是所要找的结点且后面还有结点
{
p2=p1;
p1=p1->next;
}
if(num==p1->num)
{
if(p1==head) head=p1->next;//若p1指向的是首结点
else p2->next=p1->next;
printf("删除%d号学生成功!",num);
n=n-1;
}
else
printf("没有找到%d",num);
return(head);
}
void print(struct student *head) //输出链表的函数
{
struct student *p;
p=head;
printf("\n学生成绩为:\n");
printf("\t学号\t姓名\t成绩\n_______________________________________________________________\n");
if(head!=NULL)
do
{
printf("\t%d\t%s\t%d\n",p->num,p->name,p->score);
p=p->next;
}while(p!=NULL);
printf("总共有%d名学生",n);
}
void search(struct student *head,int num)//对链表的查询
{
struct student *p;
if(head==NULL)
printf("\n该表是空表!\n");
p=head;
if(p->num==num)
{
printf("该学生信息为:\n\n");
printf("\t学号\t姓名\t成绩\n\t%d\t%s\n",p->num,p->name,p->score);
}
else
{
while(p!=NULL)
{
p=p->next;
if(p!=NULL&&p->num==num)
{
break;
}
}
if(p==NULL) printf("\t不存在该学号的学生!");
else
{
printf("该学生信息为:\n\n");
printf("\t学号\t姓名\t成绩\n\t%d\t%s\n",p->num,p->name,p->score);
}
}
}
void chucun(struct student *head)
{
struct student *p;
FILE *fp;
p=head;
fp=fopen("stud.dat","w");
while(p!=NULL)
{
if(fwrite(p,LEN,1,fp)!=1)
printf("数据存储失败!");
p=p->next;
}
fclose(fp);
}
void daochu(struct student *head)
{
struct student *p;
FILE *fp;
p=head;
fp=fopen("stud.dat","w");
printf("\t学号\t姓名\t成绩\n_______________________________________________\n");
while(p!=NULL)
{
fread(p,LEN,1,fp);
printf("\t%d\t%s\t%d\n",p->num,p->name,p->score);
p=p->next;
}
} 本帖最后由 jackz007 于 2021-1-7 15:24 编辑
读取和保存链表的代码有些草率了,尤其是从文件中读取,不可以只是简单的从文件中整体读出整个链表,因为从文件中读取节点的 next 中保存的是当时下一个节点的内存地址,显然不能直接使用,必须是逐节点读出,然后,重新链接。
以下代码重点修改了 main()、chucun()、daochu() 3 个函数
#include <stdio.h>
#include <malloc.h>
#define LEN sizeof(struct student)
struct student
{
int num ;
char name ;
int score ;
struct student * next ;
} ;
int n;//统计学生人数
struct student *creat();
struct student *insert(struct student *head,struct student *stud);
struct student *del(struct student *head ,int num);
void print(struct student *head);
void search(struct student *head,int num);
void chucun(struct student *head);
void daochu(struct student **head); //函数声明
int main()
{
struct student *head,*stu ;
int f , del_num , ser_num , i ;
for(f = 1 ; f ;) {
printf("\n\t学生管理系统1.0\n\n");
printf("--------------菜单--------------\n\n");
printf("\t1.登记学生信息\n");
printf("\t2.删除学生信息\n");
printf("\t3.增加学生信息\n");
printf("\t4.查找学生信息\n");
printf("\t5.浏览学生信息\n");
printf("\t6.储存到文件\n");
printf("\t7.从文件导出\n");
printf("\t8.退出系统\n") ;
printf("\n说明:学生信息输入0,表示输入结束\n\n");
printf("请选择:") ;
fflush(stdin) ;
scanf("%d", & i) ;
if(i > 0 && i < 9) {
switch(i) {
case 1: head=creat();break;
case 2:
printf("请输入要删除的学号:");
scanf("%d",&del_num);
while(del_num!=0) {
head=del(head,del_num);
printf("请输入要删除的学号:");
scanf("%d",&del_num);
}
break;
case 3:
printf("请输入要增加的学生的信息\n");
printf("请输入学号,姓名(用逗号隔开):");
stu=(struct student *)malloc(LEN);
scanf("%d,%s",&stu->num,&stu->name);
printf("请输入分数:");
scanf("%d",&stu->score);
while(stu->num!=0) {
head=insert(head,stu);
printf("请输入要增加的学生的信息\n");
printf("请输入学号,姓名(用逗号隔开):");
stu=(struct student *)malloc(LEN);
scanf("%d,%s",&stu->num,&stu->name);
printf("请输入分数:");
scanf("%d",&stu->score);
}
break;
case 4:
printf("请输入要查找学生的学号:");
scanf("%d",&ser_num);
search(head,ser_num);
break;
case 5: print(head);break;
case 6: chucun(head);break;
case 7: daochu(& head);break;
case 8: f = 0 ; break ;
}
} else {
printf("\n") ;
printf("请输入1-8之间的数字!!!\n");
printf("\n") ;
}
}
}
struct student *creat() //建立链表的函数
{
struct student *head,*p1,*p2;
n=0;
p1=p2=(struct student *)malloc(LEN);
printf("请输入学号,姓名(用逗号隔开):");
scanf("%d,%s",&p1->num,&p1->name);
printf("请输入分数:");
scanf("%d",&p1->score);
head=NULL;
while(p1->num!=0)
{
n=n+1;
if(n==1) head=p1;
else p2->next=p1;
p2=p1;
p1=(struct student *)malloc(LEN);
printf("请输入学号,姓名(用逗号隔开):");
scanf("%d,%s",&p1->num,&p1->name);
printf("请输入分数:");
scanf("%d",&p1->score);
}
p2->next=NULL;
return head;
}
struct student *insert(struct student *head,struct student *stud)//插入结点的函数
{
struct student *p0,*p1,*p2;
p1=head;
p0=stud; //指向要插入的结点
if(head==NULL) //如果为空链表
{
head=p0;
p0->next=NULL;
}
else
{
while((p0->num>p1->num)&&(p1->next!=NULL))
{
p2=p1;
p1=p1->next;
}
}
if(p0->num<=p1->num)
{
if(head==p1) head=p0;//插入的是头结点
else p2->next=p0; //插入的是中间结点
p0->next=p1;
}
else //插入的是尾结点
{
p1->next=p0;
p0->next=NULL;
}
n=n+1;
return(head);
}
struct student *del(struct student *head ,int num)//删除结点的函数
{
struct student *p1,*p2;
if(head==NULL)
{
printf("\n该表是空表!\n");
return(head);
}
p1=head;
while(num!=p1->num&&p1->next!=NULL)//p1指向的不是所要找的结点且后面还有结点
{
p2=p1;
p1=p1->next;
}
if(num==p1->num)
{
if(p1==head) head=p1->next;//若p1指向的是首结点
else p2->next=p1->next;
printf("删除%d号学生成功!",num);
n=n-1;
}
else
printf("没有找到%d",num);
return(head);
}
void print(struct student *head) //输出链表的函数
{
struct student *p;
p=head;
printf("\n学生成绩为:\n");
printf("\t学号\t姓名\t成绩\n_______________________________________________________________\n");
if(head!=NULL)
do
{
printf("\t%d\t%s\t%d\n",p->num,p->name,p->score);
p=p->next;
}while(p!=NULL);
printf("总共有%d名学生",n);
}
void search(struct student *head,int num)//对链表的查询
{
struct student *p;
if(head==NULL)
printf("\n该表是空表!\n");
p=head;
if(p->num==num)
{
printf("该学生信息为:\n\n");
printf("\t学号\t姓名\t成绩\n\t%d\t%s\n",p->num,p->name,p->score);
}
else
{
while(p!=NULL)
{
p=p->next;
if(p!=NULL&&p->num==num)
{
break;
}
}
if(p==NULL) printf("\t不存在该学号的学生!");
else
{
printf("该学生信息为:\n\n");
printf("\t学号\t姓名\t成绩\n\t%d\t%s\n",p->num,p->name,p->score);
}
}
}
void chucun(struct student * head)
{
FILE * fp ;
char fn[] = "stu.dat" ;
if((fp = fopen(fn , "wb")) != NULL) { // 【关键】必须是为二进制写打开
for(; head ; head = head -> next) {
fwrite(head , sizeof(struct student) , 1 , fp) ;
}
fclose(fp) ;
} else {
fprintf(stderr , "\n") ;
fprintf(stderr , "无法创建记录文件 [\"%s\"] !\n" , fn) ;
fprintf(stderr , "\n") ;
}
}
void daochu(struct student ** head) // 【关键】通过 head 反馈链表头节点,得用二级指针
{
struct student * p , * q , stu ;
FILE * fp ;
char fn[] = "stu.dat" ;
* head = NULL ; // 【关键】读取数据前,必须先将头节点地址置空
if((fp = fopen(fn , "rb")) != NULL) { // 【关键】必须是为二进制读打开
fread(& stu , sizeof(struct student) , 1 , fp) ;
while(! feof(fp)) {
if((p = (struct student *) malloc(sizeof(struct student))) != NULL) { // 【关键】节点数据有效才分配内存
* p = stu ;
p -> next = NULL ;
if(* head) q -> next = p ;
else * head = p ;
q = p ;
fread(& stu , sizeof(struct student) , 1 , fp) ;
} else {
for(p = * head ; p ; p = q) {
q = p -> next ;
free(p) ;
}
fprintf(stderr , "\n") ;
fprintf(stderr , "内存分配失败 !\n") ;
fprintf(stderr , "\n") ;
}
}
fclose(fp) ;
if(* head) {
printf("\t学号\t姓名\t成绩\n_______________________________________________\n");
for(p = * head ; p ; p = p -> next) {
printf("\t%d\t%s\t%d\n",p->num,p->name,p->score) ;
}
}
} else {
fprintf(stderr , "\n") ;
fprintf(stderr , "记录文件 [\"%s\"] 不存在!\n" , fn) ;
fprintf(stderr , "\n") ;
}
} jackz007 发表于 2021-1-7 14:36
读取和保存链表的代码有些草率了,尤其是从文件中读取,不可以只是简单的从文件中整体读出整个链表 ...
感谢大佬{:10_275:}
页:
[1]