鱼C论坛

 找回密码
 立即注册
查看: 2507|回复: 1

请教链表和文件打开存储问题

[复制链接]
发表于 2017-4-23 23:31:16 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能^_^

您需要 登录 才可以下载或查看,没有账号?立即注册

x
学链表没多久时间,作业要求用到链表跟文件存储,加了进去,使用Vs2015编译没什么问题,但调试时发现打开文件读取数据出现“读取字符串的字符出错”和“字符串中的字符无效”的提示,然后录入功能觉得数据没有链接上节点,后面其他功能我觉得写的算法好像没问题,但都不能正常运行,希望大家能我一些修改意见,说一下我哪里有错,学习一下。
  1. #include<stdio.h>    //其中包含feof();
  2. #include<string.h>   //包含strcmp(); strchr(); strcpy();
  3. #include<stdlib.h>   //包含malloc(); free(); system(); exit();
  4. #include<io.h>         //为access()提供定义
  5. #define BROWSE printf("书名 \t 作者 \t 归属分类 \t 出版社 \t 出版时间 \t ISBN码 \t 价格\n");_ui(); printf("%s \t %s \t %s", current->book_name, current->author, current->classification); printf("%s \t %s \t %s \t %0.2lf\n", current->press, current->publish_time, current->ISBN, current->price);_ui();

  6. typedef struct book {
  7.         char ISBN[15];
  8.         char book_name[30];
  9.         char author[20];
  10.         char classification[20];
  11.         char press[30];
  12.         char publish_time[5];
  13.         double price;
  14.         struct book *next;
  15. }library;    // ISBN码,书名,作者名,分类名,出版单位,出版时间,价格等

  16. void _ui() //菜单分割线
  17. {
  18.         printf("\t\t");
  19.         for (int i = 0; i<49; i++)
  20.                 printf("-");
  21.         printf("\n");
  22. }
  23. void main_menu() //主菜单
  24. {
  25.         system("color F0");  //背景色及字体
  26.         _ui(); printf("\t\t|\t\t图书信息管理系统\t\t|\n"); _ui();
  27.         printf("\t\t|\t\t1:录入\t\t\t\t|\n"); _ui();
  28.         printf("\t\t|\t\t2:浏览\t\t\t\t|\n"); _ui();
  29.         printf("\t\t|\t\t3:查询\t\t\t\t|\n"); _ui();
  30.         printf("\t\t|\t\t4:排序\t\t\t\t|\n"); _ui();
  31.         printf("\t\t|\t\t5:删除与修改\t\t\t|\n"); _ui();
  32.         printf("\t\t|\t\t6:保存到文件\t\t\t|\n"); _ui();
  33.         printf("\t\t|\t\t7:退出\t\t\t\t|\n"); _ui();
  34.         printf("\t\t输入你的选项(1~7):");
  35. }
  36. library * _search(const library * prev,char *keywords,int choice)   //查找节点
  37. {
  38.         //choice的值,1对应书名查找,2对应作者查找,3对应ISBN码查找
  39.         library * temp = prev->next;
  40.         switch (choice) {
  41.         case 1: for (; temp->next != NULL&&temp->book_name != keywords; temp = temp->next); break;
  42.         case 2: for (; temp->next != NULL&&temp->author != keywords; temp = temp->next); break;
  43.         case 3: for (; temp->next != NULL&&temp->ISBN != keywords; temp = temp->next); break;
  44.         }
  45.         return temp;
  46. }
  47. char * ch_gets(char * ch, int n) //专用于输入是否有效以及清除多余的‘\n’,参考C primer plus代码中代码,只为字符输入,但有效减少输入流里的'\n'
  48. {
  49.         char * return_val;
  50.         char * find;
  51.         return_val = fgets(ch, n, stdin); //fgets()函数会录入'\n',相对应的fputs不会添加'\n',ch对应指针,n对应需要的字符串大小(用于限定大小还是挺好的),stdin标准输入流
  52.         if (return_val)
  53.         {
  54.                 find = strchr(ch, '\n'); //检查ch的指针指向的内容,这样是查找ch里的'\n',匹配就把地址赋给find;
  55.                 if (find)                      //判断find是否为NULL
  56.                         *find = '\0';              //不是NULL的就把原来的'\n'变成'\0',
  57.                 else                            //当为空NULL时,运行下面清除可能存在的换行符
  58.                         while (getchar() != '\n')
  59.                                 continue;
  60.         }
  61.         return return_val;
  62. }
  63. library * _entry(library * book_head) //(1)录入,之前文件没有数据的则进行新数据录入,以新链表进行存储,后面返回头head地址
  64. {
  65.         char input[30];
  66.         library *head=book_head,*prev,*current;          //保存book_head传过来的地址
  67.         for (; book_head->next == NULL; book_head = book_head->next)  //调整book_head到最后一个节点的next,使后面的录入连接上
  68.                 continue;
  69.         _ui(); printf(" \t\t|\t\t图书信息管理系统:录入\t\t|\n"); _ui();
  70.         if ((book_head->next = prev = current = (struct book *)malloc(sizeof(library))) == NULL)  //开始分配内存,并相同指向同个位置
  71.              {puts("无法分配内存..."); system("pause"); return NULL;}
  72.         printf("添加一本新书的名字(回车则返回菜单):\n");
  73.         while (ch_gets(input, 30) != NULL&& input[0] != '\0')
  74.         {
  75.                 if ((current = (struct book *)malloc(sizeof(library))) == NULL)
  76.                     {puts("无法分配内存..."); system("pause"); return NULL;}
  77.                 strcpy(current->book_name, input);
  78.                 puts("输入作者名:");
  79.                 ch_gets(current->author, 20);
  80.                 puts("输入归属分类:");
  81.                 ch_gets(current->classification, 20);
  82.                 puts("输入出版社:");
  83.                 ch_gets(current->press, 30);
  84.                 puts("输入出版时间:");
  85.                 ch_gets(current->publish_time, 5);
  86.                 puts("输入ISBN码:");
  87.                 ch_gets(current->ISBN, 15);
  88.                 puts("输入价格:");
  89.                 scanf("%lf", &current->price); while (getchar() != '\n') continue;
  90.                 puts("继续输入新书名(直接回车返回主菜单):");
  91.                 prev->next=current;  //第一次current指向head,后面的就是上次的perv->next
  92.                 prev = current;        //把当前的current指向perv,用于下次的指向;
  93.         }
  94.         prev->next = NULL;
  95.         return head;
  96. }
  97. void _browse(const library *head) //(2)浏览,只需要链表首地址
  98. {
  99.         const library *current= head;
  100.         char choice[2] = {'u'};
  101.         _ui(); printf("\t\t|\t图书信息管理系统:浏览(回车返回主菜单)\t|\n"); _ui();
  102.         if (head == NULL)
  103.         {
  104.                 puts("没有数据");
  105.                 system("pause");
  106.                 return;
  107.         }
  108.         else
  109.                 if (head->next == NULL) //判断是否为一个节点
  110.                 {
  111.                         if (!head->book_name) //判断有无数据   系统是否会有垃圾值??
  112.                         {
  113.                                 BROWSE;
  114.                         }
  115.                 }
  116.                 else
  117.                 {
  118.                         printf("书名 \t 作者 \t 归属分类 \t 出版社 \t 出版时间 \t ISBN码 \t 价格\n"); _ui();
  119.                         current = head;
  120.                         for (current = current->next; current != NULL; current = current->next)
  121.                         {
  122.                                 printf("%s \t %s \t %s", current->book_name, current->author, current->classification);
  123.                                 printf("%s \t %s \t %s \t %0.2lf\n", current->press, current->publish_time, current->ISBN, current->price); _ui();
  124.                                 current = current->next;
  125.                         }
  126.                 }
  127.                 system("pause");
  128. }
  129. void _inquire(const library *head) //(3)查询
  130. {
  131.         char choice, select[30];
  132.         const library *current=head;
  133.         _ui(); printf("\t\t|\t\t图书信息管理系统:查询\t\t|\n"); _ui();//书名或作者名查询
  134.         printf("Y:默认书名查询,N:作者名查询,回车返回菜单(Y/N):");
  135.         while (ch_gets(&choice, 1) != NULL&& choice != '\0')
  136.         {
  137.                 if (choice == 'Y' || choice == 'y')
  138.                 {
  139.                         puts("输入书名:");
  140.                         ch_gets(select, 30);
  141.                         current = _search(current,select,1);
  142.                         if (current != NULL) //能找找到匹配项时
  143.                              {BROWSE; system("pause");}
  144.                         else
  145.                         {puts("没有结果"); system("pause");}
  146.                 }
  147.                 else if (choice == 'N' || choice == 'n')
  148.                 {
  149.                         puts("输入作者名:");
  150.                         ch_gets(select, 30);
  151.                         current = _search(current,select,2);
  152.                         if (current!=NULL)
  153.                              {BROWSE; system("pause");}
  154.                         else
  155.                         {puts("没有结果"); system("pause");}
  156.                 }
  157.                 else
  158.                         puts("你输入有误,请再输入:");
  159.         }
  160. }
  161. library * _sorting(library *head) //(4)排序
  162. {
  163.         char choice;
  164.         library *current= head->next, *prev= head, *temp=NULL;
  165.         if ((temp = (struct book *)malloc(sizeof(library))) == NULL)
  166.              {puts("无法分配内存..."); system("pause"); return NULL;}
  167.         _ui(); printf("\t\t|\t\t图书信息管理系统:排序\t\t|\n"); _ui();//书名或价格排序
  168.         printf("Y:默认书名排列,N:价格排列,回车返回菜单(Y/N):");
  169.         while (ch_gets(&choice, 1) != NULL && choice != '\0')
  170.         {
  171.                 if (choice == 'Y' || choice == 'y')//书名排序
  172.                 {
  173.                         for (; strcmp(prev->book_name, current->book_name)>0 || current != NULL; current = current->next)
  174.                         {
  175.                                 temp = prev;
  176.                                 prev = current->next;
  177.                                 current->next = temp;
  178.                         }
  179.                         _browse(head);
  180.                 }
  181.                 else if (choice == 'N' || choice == 'n')//价格排序
  182.                 {
  183.                         printf("Y:从大到小排列,N:从小到大排列,回车返回菜单(Y/N):");
  184.                         while (ch_gets(&choice, 1) != NULL&& choice != '\0')
  185.                         {
  186.                                 if (choice == 'Y' || choice == 'y')//从大到小
  187.                                 {
  188.                                         for (; prev->price > current->price || current != NULL; current = current->next)
  189.                                         {
  190.                                                 temp = prev;
  191.                                                 prev = current->next;
  192.                                                 current->next = temp;
  193.                                         }
  194.                                         _browse(head);
  195.                                 }
  196.                                 else if (choice == 'N' || choice == 'n') //从小到大
  197.                                 {
  198.                                         for (; prev->price > current->price|| current != NULL; current = current->next)
  199.                                         {
  200.                                                 temp = current->next;
  201.                                                 current->next = prev;
  202.                                                 prev = temp;
  203.                                                 free(temp);
  204.                                         }
  205.                                         _browse(head);
  206.                                 }
  207.                         }
  208.                 }
  209.                 else
  210.                 {
  211.                         puts("你输入有误,请再输入:");
  212.                         scanf("%c", &choice);
  213.                 }
  214.         }
  215.         free(temp);
  216.         return head;
  217. }
  218. library * menu_modify(library *current) //用于下面”_delete_modify“函数的删除与修改的选项菜单以及其功能实现
  219. {
  220.         char choice;
  221.         _ui(); printf("\t\t|\t\t图书信息管理系统:删除与修改(操作菜单)\t|\n"); _ui();
  222.         printf("\t\t|(1)书名\t\t(2)作者\t\t|\n"); _ui();
  223.         printf("\t\t|(3)归属分类 \t\t(4)出版社\t\t|\n"); _ui();
  224.         printf("\t\t|(5)出版时间 \t\t(6)ISBN码\t\t|\n"); _ui();
  225.         printf("\t\t|(7)价格  \t\t(8)删除此条记录\t|\n"); _ui();
  226.         puts("选择的操作数据的选项(回车取消操作,返回上一层):\n");
  227.         while (ch_gets(&choice, 1) != NULL&& choice != '\0')
  228.         {
  229.                 switch (choice) {
  230.                 case 1:
  231.                         puts("输入你修改的书名:");
  232.                         ch_gets(current->book_name, 20); break;
  233.                 case 2:
  234.                         puts("输入你修改的作者:");
  235.                         ch_gets(current->author, 20); break;
  236.                 case 3:
  237.                         puts("输入你修改的归属分类:");
  238.                         ch_gets(current->classification, 20); break;
  239.                 case 4:
  240.                         puts("输入你修改的出版社:");
  241.                         ch_gets(current->press, 30); break;
  242.                 case 5:
  243.                         puts("输入你修改的出版时间:");
  244.                         ch_gets(current->publish_time, 5); break;
  245.                 case 6:
  246.                         puts("输入你修改的ISBN码:");
  247.                         ch_gets(current->ISBN, 5); break;
  248.                 case 7:
  249.                         puts("输入你修改的价格:");
  250.                         scanf("%lf", &current->price); while (getchar() != '\n') continue; break;
  251.                 case 8:current = current->next; return NULL; break;
  252.                 }
  253.         }
  254.                 return current;
  255. }
  256. library * _delete_modify(library *head) //(5)删除与修改
  257. {
  258.         library *current=head;
  259.         char temp_input[30];
  260.         _ui(); printf("\t\t|\t\t图书信息管理系统:删除与修改\t|\n"); _ui();
  261.         printf("\t\t默认匹配修改,回车返回主菜单\n");
  262.         printf("输入书名或ISBN码:");
  263.         while (ch_gets(temp_input, 30) != NULL&& temp_input[0] != '\0')
  264.         {
  265.                         current = _search(current,temp_input,1); //使用书名查找
  266.                         current = _search(current, temp_input,3); //使用ISBN码查找
  267.                         if(current!=NULL)
  268.                         {
  269.                                 BROWSE;
  270.                                 _ui(); current=menu_modify(current);
  271.                                 if(current!=NULL)   //删除时不显示修改后结果
  272.                                 BROWSE;
  273.                                 system("pause");
  274.                         }
  275.                         else
  276.                                 puts("你输入有误,请再输入:");
  277.         }
  278.         return head;
  279. }
  280. library * open_file() //打开文件,参考修改
  281. {
  282.         FILE *fbook;
  283.         library *prev,*current,*head;
  284.         if (access("book_mg.txt", 0)==0) //判断文件是否存在,存在返回零
  285.                 fbook = fopen("book_mg.dat", "rb");
  286.         else
  287.         {
  288.                 fbook = fopen("book_mg.dat", "a");
  289.                 fclose(fbook); puts("创建book_mg.dat成功");
  290.                 fbook = fopen("book_mg.dat", "rb");
  291.         }
  292.         if ((head = current = prev = (library *)malloc(sizeof(library))) == NULL)    //使三个指针的地址相同,首地址head确定
  293.              {puts("无法分配内存..."); system("pause"); return NULL;}
  294.         else
  295.                 head->price=0; //类似的再次确定内存可访问;随意让首地址确定下来,觉得返回NULL不好。并将其中的成员赋值,原因是因为如果文件没内容时,head指针跟空了似的,好像把初始出来的内存垃圾值给其成员
  296.         if (fbook == '\0') //判断文件是否有内容
  297.         {
  298.                 fclose(fbook);
  299.         }
  300.         else
  301.         {
  302.                 while (!feof(fbook)) //返回非零值代表已到达文件尾.说明零值时文件还有数据可输入
  303.                 {
  304.                         if ((current = (library *)malloc(sizeof(library))) == NULL)
  305.                               {puts("无法分配内存..."); system("pause"); return NULL;}
  306.                         fread(current, sizeof(library), 1, fbook); //二进制读取,因为书的价格是double类型,为不丢失精度
  307.                         //fscanf(fbook,"%s %s %s %s %s %s %lf", current->book_name, current->author, current->classification, current->press, current->publish_time, current->ISBN, &current->price); //文本模式读取
  308.                         prev->next = current;    //因为prev在上面确定首地址时已经把prev地址指向head,第一次运行说明第一个current指向head->head
  309.                         prev = current;            //为下次输入进行保留本次地址
  310.                 }
  311.                 prev->next = NULL;//最后完成输入的节点需要最后的指针指空,不然会变野指针
  312.                 fclose(fbook);
  313.         }
  314.         return head;
  315. }

  316. void  _save(library *head) //(7)存储
  317. {
  318.         FILE *fbook;
  319.         library *prev = head;
  320.         _ui(); printf("\t\t|\t图书信息管理系统:保存到文件\t\t|\n"); _ui();
  321.         if ((fbook = fopen("book_mg.txt", "wb")) == NULL)
  322.         {puts("文件不能打开...");return;}
  323.         if (head->next != NULL)  //说明还有节点可以输入保存到文件里
  324.         {
  325.                 for (prev=prev->next; prev != NULL; prev = prev->next)   //最开始prev指向了head,而由于打开文件时初始化的head是没有用的,所以prev=prev->next;舍弃第一个节点从第二个开始存
  326.                         fwrite(prev, sizeof(library), 1, fbook);  //二进制保存
  327.                         //fprintf(fbook, "%s %s %s %s %s %s %lf", prev->book_name, prev->author, prev->classification, prev->press, prev->publish_time, prev->ISBN, prev->price);  //保存
  328.         }
  329.         fclose(fbook);
  330.         puts("保存完毕..."); system("pause");
  331. }

  332. int main(void)  //
  333. {
  334.         int choice=-1;
  335.         library * book_head=open_file(); //初始化,并给首地址
  336.         while (1)
  337.         {
  338.                 system("cls");
  339.                 main_menu();
  340.                 if (scanf("%d", &choice)) //选项选择,带纠错
  341.                 {
  342.                         if ((choice > 1 && 7 < choice))
  343.                                 printf("你的输入有误,请再输入:");
  344.                 }
  345.                 system("cls");
  346.                 while (getchar() != '\n') //防止'\n'
  347.                         continue;
  348.                 switch (choice) {
  349.                 case 1:book_head=_entry(book_head);break;      //(1)录入

  350.                 case 2:_browse(book_head); break; //(2)浏览

  351.                 case 3:_inquire(book_head); break; //(3)查询

  352.                 case 4:book_head=_sorting(book_head); break;  //(4)排序

  353.                 case 5:book_head=_delete_modify(book_head); break; //(5)删除与修改

  354.                 case 6:_save(book_head); break; //(6)存储

  355.                 case 7:free(book_head);
  356.                         exit(0);
  357.                 }
  358.         }
  359.         return 0;
  360. }
复制代码
小甲鱼最新课程 -> https://ilovefishc.com
回复

使用道具 举报

 楼主| 发表于 2017-4-27 11:41:35 | 显示全部楼层
后面研究得结果是链表分配就有错误,文件没问题,但还是没有头绪怎么改,准备要交了,希望大家给我点指点~~感谢了!!
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

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

本版积分规则

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

GMT+8, 2025-6-9 03:41

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

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