闹够了 发表于 2021-1-7 13:11:01

为什么用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 14:36:27

本帖最后由 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")                                             ;
      }
}

闹够了 发表于 2021-1-7 18:51:19

jackz007 发表于 2021-1-7 14:36
读取和保存链表的代码有些草率了,尤其是从文件中读取,不可以只是简单的从文件中整体读出整个链表 ...

感谢大佬{:10_275:}
页: [1]
查看完整版本: 为什么用fwrite写入文件中,关闭程序重新打开读这个文件会不行