鱼C论坛

 找回密码
 立即注册
查看: 1186|回复: 2

[已解决]为什么用fwrite写入文件中,关闭程序重新打开读这个文件会不行

[复制链接]
发表于 2021-1-7 14:36:27 | 显示全部楼层    本楼为最佳答案   
本帖最后由 jackz007 于 2021-1-7 15:24 编辑

       读取和保存链表的代码有些草率了,尤其是从文件中读取,不可以只是简单的从文件中整体读出整个链表,因为从文件中读取节点的 next 中保存的是当时下一个节点的内存地址,显然不能直接使用,必须是逐节点读出,然后,重新链接。
       以下代码重点修改了 main()、chucun()、daochu() 3 个函数
  1. #include <stdio.h>
  2. #include <malloc.h>

  3. #define LEN sizeof(struct student)

  4. struct student
  5. {
  6.         int num               ;
  7.         char name[10]         ;
  8.         int score             ;
  9.         struct student * next ;
  10. }                             ;

  11. int n;  //统计学生人数

  12. struct student *creat();
  13. struct student *insert(struct student *head,struct student *stud);
  14. struct student *del(struct student *head ,int num);
  15. void print(struct student *head);
  16. void search(struct student *head,int num);
  17. void chucun(struct student *head);
  18. void daochu(struct student **head);             //函数声明

  19. int main()
  20. {
  21.         struct student *head,*stu ;
  22.         int f , del_num , ser_num , i ;
  23.         for(f = 1 ; f ;) {
  24.                 printf("\n\t学生管理系统1.0\n\n");
  25.                 printf("--------------菜单--------------\n\n");
  26.                 printf("\t1.登记学生信息\n");
  27.                 printf("\t2.删除学生信息\n");
  28.                 printf("\t3.增加学生信息\n");
  29.                 printf("\t4.查找学生信息\n");
  30.                 printf("\t5.浏览学生信息\n");
  31.                 printf("\t6.储存到文件\n")  ;
  32.                 printf("\t7.从文件导出\n")  ;
  33.                 printf("\t8.退出系统\n")    ;
  34.                 printf("\n说明:学生信息输入0,表示输入结束\n\n");
  35.                 printf("请选择:")          ;
  36.                 fflush(stdin)               ;
  37.                 scanf("%d", & i)            ;
  38.                 if(i > 0 && i < 9) {
  39.                         switch(i) {
  40.                                 case 1: head=creat();break;
  41.                                 case 2:
  42.                                 printf("请输入要删除的学号:");
  43.                                 scanf("%d",&del_num);
  44.                                         while(del_num!=0) {
  45.                                                 head=del(head,del_num);
  46.                                                 printf("请输入要删除的学号:");
  47.                                                 scanf("%d",&del_num);
  48.                                         }
  49.                                         break;
  50.                                 case 3:
  51.                                         printf("请输入要增加的学生的信息\n");
  52.                                         printf("请输入学号,姓名(用逗号隔开):");
  53.                                         stu=(struct student *)malloc(LEN);
  54.                                         scanf("%d,%s",&stu->num,&stu->name);
  55.                                         printf("请输入分数:");
  56.                                         scanf("%d",&stu->score);
  57.                                         while(stu->num!=0) {
  58.                                                 head=insert(head,stu);
  59.                                                 printf("请输入要增加的学生的信息\n");
  60.                                                 printf("请输入学号,姓名(用逗号隔开):");
  61.                                                 stu=(struct student *)malloc(LEN);
  62.                                                 scanf("%d,%s",&stu->num,&stu->name);
  63.                                                 printf("请输入分数:");
  64.                                                 scanf("%d",&stu->score);
  65.                                         }
  66.                                         break;
  67.                                 case 4:
  68.                                         printf("请输入要查找学生的学号:");
  69.                                         scanf("%d",&ser_num);
  70.                                         search(head,ser_num);
  71.                                         break;
  72.                                 case 5: print(head);break;
  73.                                 case 6: chucun(head);break;
  74.                                 case 7: daochu(& head);break;
  75.                                 case 8: f = 0 ; break ;
  76.                         }
  77.                 } else {
  78.                         printf("\n")                         ;
  79.                         printf("请输入1-8之间的数字!!!\n");
  80.                         printf("\n")                         ;
  81.                 }
  82.         }
  83. }

  84. struct student *creat()   //建立链表的函数
  85. {
  86.         struct student *head,*p1,*p2;
  87.         n=0;
  88.         p1=p2=(struct student *)malloc(LEN);
  89.         printf("请输入学号,姓名(用逗号隔开):");
  90.         scanf("%d,%s",&p1->num,&p1->name);
  91.         printf("请输入分数:");
  92.         scanf("%d",&p1->score);
  93.         head=NULL;
  94.         while(p1->num!=0)
  95.         {
  96.                 n=n+1;
  97.                 if(n==1) head=p1;
  98.                 else p2->next=p1;
  99.                 p2=p1;
  100.                 p1=(struct student *)malloc(LEN);
  101.                 printf("请输入学号,姓名(用逗号隔开):");
  102.                 scanf("%d,%s",&p1->num,&p1->name);
  103.                 printf("请输入分数:");
  104.                 scanf("%d",&p1->score);
  105.         }
  106.         p2->next=NULL;
  107.         return head;
  108. }

  109. struct student *insert(struct student *head,struct student *stud)  //插入结点的函数
  110. {
  111.         struct student *p0,*p1,*p2;
  112.         p1=head;
  113.         p0=stud;         //指向要插入的结点
  114.         if(head==NULL)   //如果为空链表
  115.         {
  116.                 head=p0;
  117.                 p0->next=NULL;
  118.         }
  119.         else
  120.         {
  121.                 while((p0->num>p1->num)&&(p1->next!=NULL))
  122.                 {
  123.                         p2=p1;
  124.                         p1=p1->next;
  125.                 }
  126.         }
  127.         if(p0->num<=p1->num)
  128.         {
  129.                 if(head==p1) head=p0;  //插入的是头结点
  130.                 else p2->next=p0;      //插入的是中间结点
  131.                 p0->next=p1;
  132.         }
  133.         else                      //插入的是尾结点
  134.         {
  135.                 p1->next=p0;
  136.                 p0->next=NULL;
  137.         }
  138.         n=n+1;
  139.         return(head);
  140. }

  141. struct student *del(struct student *head ,int num)  //删除结点的函数
  142. {
  143.         struct student *p1,*p2;
  144.         if(head==NULL)
  145.         {
  146.                 printf("\n该表是空表!\n");
  147.                 return(head);
  148.         }
  149.         p1=head;
  150.         while(num!=p1->num&&p1->next!=NULL)  //p1指向的不是所要找的结点且后面还有结点
  151.         {
  152.                 p2=p1;
  153.                 p1=p1->next;
  154.         }
  155.         if(num==p1->num)
  156.         {
  157.                 if(p1==head) head=p1->next;  //若p1指向的是首结点
  158.                 else p2->next=p1->next;
  159.                 printf("删除%d号学生成功!",num);
  160.                 n=n-1;
  161.         }
  162.         else
  163.                 printf("没有找到%d",num);
  164.         return(head);
  165. }

  166. void print(struct student *head)      //输出链表的函数
  167. {
  168.         struct student *p;
  169.         p=head;
  170.         printf("\n学生成绩为:\n");
  171.         printf("\t学号\t姓名\t成绩\n_______________________________________________________________\n");
  172.         if(head!=NULL)
  173.                 do
  174.                 {
  175.                         printf("\t%d\t%s\t%d\n",p->num,p->name,p->score);
  176.                         p=p->next;
  177.                 }while(p!=NULL);
  178.         printf("总共有%d名学生",n);
  179. }

  180. void search(struct student *head,int num)  //对链表的查询
  181. {
  182.         struct student *p;
  183.         if(head==NULL)
  184.                 printf("\n该表是空表!\n");
  185.         p=head;
  186.         if(p->num==num)
  187.         {
  188.                 printf("该学生信息为:\n\n");
  189.                 printf("\t学号\t姓名\t成绩\n\t%d\t%s\n",p->num,p->name,p->score);
  190.         }
  191.         else
  192.         {
  193.                 while(p!=NULL)
  194.                 {
  195.                         p=p->next;
  196.                         if(p!=NULL&&p->num==num)
  197.                         {
  198.                                 break;
  199.                         }
  200.                 }
  201.                 if(p==NULL) printf("\t不存在该学号的学生!");
  202.                 else
  203.                 {
  204.                         printf("该学生信息为:\n\n");
  205.                         printf("\t学号\t姓名\t成绩\n\t%d\t%s\n",p->num,p->name,p->score);
  206.                 }
  207.         }
  208. }

  209. void chucun(struct student * head)
  210. {
  211.         FILE * fp                                                                  ;
  212.         char fn[] = "stu.dat"                                                      ;
  213.         if((fp = fopen(fn , "wb")) != NULL) {                                                 // 【关键】必须是为二进制写打开
  214.                 for(; head ; head = head -> next) {
  215.                         fwrite(head , sizeof(struct student) , 1 , fp)             ;
  216.                 }
  217.                 fclose(fp)                                                         ;
  218.         } else {
  219.                 fprintf(stderr , "\n")                                             ;
  220.                 fprintf(stderr , "无法创建记录文件 ["%s"] !\n" , fn)            ;
  221.                 fprintf(stderr , "\n")                                             ;
  222.         }
  223. }

  224. void daochu(struct student ** head)                                                           // 【关键】通过 head 反馈链表头节点,得用二级指针
  225. {
  226.         struct student * p , * q , stu                                             ;
  227.         FILE * fp                                                                  ;
  228.         char fn[] = "stu.dat"                                                      ;
  229.         * head = NULL                                                              ;          // 【关键】读取数据前,必须先将头节点地址置空
  230.         if((fp = fopen(fn , "rb")) != NULL) {                                                 // 【关键】必须是为二进制读打开
  231.                 fread(& stu , sizeof(struct student) , 1 , fp)                     ;
  232.                 while(! feof(fp)) {
  233.                         if((p = (struct student *) malloc(sizeof(struct student))) != NULL) { // 【关键】节点数据有效才分配内存
  234.                                 * p = stu                                          ;
  235.                                 p -> next = NULL                                   ;
  236.                                 if(* head) q -> next = p                           ;
  237.                                 else * head = p                                    ;
  238.                                 q = p                                              ;
  239.                                 fread(& stu , sizeof(struct student) , 1 , fp)     ;
  240.                         } else {
  241.                                 for(p = * head ; p ; p = q) {
  242.                                         q = p -> next                              ;
  243.                                         free(p)                                    ;
  244.                                 }
  245.                                 fprintf(stderr , "\n")                             ;
  246.                                 fprintf(stderr , "内存分配失败 !\n")               ;
  247.                                 fprintf(stderr , "\n")                             ;
  248.                         }
  249.                 }
  250.                 fclose(fp)                                                         ;
  251.                 if(* head) {
  252.                         printf("\t学号\t姓名\t成绩\n_______________________________________________\n");
  253.                         for(p = * head ; p ; p = p -> next) {
  254.                                 printf("\t%d\t%s\t%d\n",p->num,p->name,p->score)   ;
  255.                         }
  256.                 }
  257.         } else {
  258.                 fprintf(stderr , "\n")                                             ;
  259.                 fprintf(stderr , "记录文件 ["%s"] 不存在!\n" , fn)              ;
  260.                 fprintf(stderr , "\n")                                             ;
  261.         }
  262. }
复制代码
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Archiver|鱼C工作室 ( 粤ICP备18085999号-1 | 粤公网安备 44051102000585号)

GMT+8, 2026-4-2 01:29

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表