鱼C论坛

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

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

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

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

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

x
学链表没多久时间,作业要求用到链表跟文件存储,加了进去,使用Vs2015编译没什么问题,但调试时发现打开文件读取数据出现“读取字符串的字符出错”和“字符串中的字符无效”的提示,然后录入功能觉得数据没有链接上节点,后面其他功能我觉得写的算法好像没问题,但都不能正常运行,希望大家能我一些修改意见,说一下我哪里有错,学习一下。
#include<stdio.h>    //其中包含feof(); 
#include<string.h>   //包含strcmp(); strchr(); strcpy();
#include<stdlib.h>   //包含malloc(); free(); system(); exit();
#include<io.h>         //为access()提供定义
#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();

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

void _ui() //菜单分割线
{
        printf("\t\t");
        for (int i = 0; i<49; i++)
                printf("-");
        printf("\n");
}
void main_menu() //主菜单
{
        system("color F0");  //背景色及字体
        _ui(); printf("\t\t|\t\t图书信息管理系统\t\t|\n"); _ui();
        printf("\t\t|\t\t1:录入\t\t\t\t|\n"); _ui();
        printf("\t\t|\t\t2:浏览\t\t\t\t|\n"); _ui();
        printf("\t\t|\t\t3:查询\t\t\t\t|\n"); _ui();
        printf("\t\t|\t\t4:排序\t\t\t\t|\n"); _ui();
        printf("\t\t|\t\t5:删除与修改\t\t\t|\n"); _ui();
        printf("\t\t|\t\t6:保存到文件\t\t\t|\n"); _ui();
        printf("\t\t|\t\t7:退出\t\t\t\t|\n"); _ui();
        printf("\t\t输入你的选项(1~7):");
}
library * _search(const library * prev,char *keywords,int choice)   //查找节点 
{
        //choice的值,1对应书名查找,2对应作者查找,3对应ISBN码查找
        library * temp = prev->next;
        switch (choice) {
        case 1: for (; temp->next != NULL&&temp->book_name != keywords; temp = temp->next); break;
        case 2: for (; temp->next != NULL&&temp->author != keywords; temp = temp->next); break;
        case 3: for (; temp->next != NULL&&temp->ISBN != keywords; temp = temp->next); break;
        }
        return temp;
}
char * ch_gets(char * ch, int n) //专用于输入是否有效以及清除多余的‘\n’,参考C primer plus代码中代码,只为字符输入,但有效减少输入流里的'\n'
{
        char * return_val;
        char * find;
        return_val = fgets(ch, n, stdin); //fgets()函数会录入'\n',相对应的fputs不会添加'\n',ch对应指针,n对应需要的字符串大小(用于限定大小还是挺好的),stdin标准输入流
        if (return_val)
        {
                find = strchr(ch, '\n'); //检查ch的指针指向的内容,这样是查找ch里的'\n',匹配就把地址赋给find;
                if (find)                      //判断find是否为NULL
                        *find = '\0';              //不是NULL的就把原来的'\n'变成'\0',
                else                            //当为空NULL时,运行下面清除可能存在的换行符
                        while (getchar() != '\n')
                                continue;
        }
        return return_val;
}
library * _entry(library * book_head) //(1)录入,之前文件没有数据的则进行新数据录入,以新链表进行存储,后面返回头head地址
{
        char input[30];
        library *head=book_head,*prev,*current;          //保存book_head传过来的地址
        for (; book_head->next == NULL; book_head = book_head->next)  //调整book_head到最后一个节点的next,使后面的录入连接上
                continue;
        _ui(); printf(" \t\t|\t\t图书信息管理系统:录入\t\t|\n"); _ui();
        if ((book_head->next = prev = current = (struct book *)malloc(sizeof(library))) == NULL)  //开始分配内存,并相同指向同个位置
             {puts("无法分配内存..."); system("pause"); return NULL;}
        printf("添加一本新书的名字(回车则返回菜单):\n");
        while (ch_gets(input, 30) != NULL&& input[0] != '\0')
        {
                if ((current = (struct book *)malloc(sizeof(library))) == NULL)
                    {puts("无法分配内存..."); system("pause"); return NULL;}
                strcpy(current->book_name, input);
                puts("输入作者名:");
                ch_gets(current->author, 20);
                puts("输入归属分类:");
                ch_gets(current->classification, 20);
                puts("输入出版社:");
                ch_gets(current->press, 30);
                puts("输入出版时间:");
                ch_gets(current->publish_time, 5);
                puts("输入ISBN码:");
                ch_gets(current->ISBN, 15);
                puts("输入价格:");
                scanf("%lf", ¤t->price); while (getchar() != '\n') continue;
                puts("继续输入新书名(直接回车返回主菜单):");
                prev->next=current;  //第一次current指向head,后面的就是上次的perv->next
                prev = current;        //把当前的current指向perv,用于下次的指向;
        }
        prev->next = NULL;
        return head;
}
void _browse(const library *head) //(2)浏览,只需要链表首地址
{
        const library *current= head;
        char choice[2] = {'u'};
        _ui(); printf("\t\t|\t图书信息管理系统:浏览(回车返回主菜单)\t|\n"); _ui();
        if (head == NULL)
        {
                puts("没有数据");
                system("pause");
                return;
        }
        else
                if (head->next == NULL) //判断是否为一个节点
                {
                        if (!head->book_name) //判断有无数据   系统是否会有垃圾值??
                        {
                                BROWSE;
                        }
                }
                else
                {
                        printf("书名 \t 作者 \t 归属分类 \t 出版社 \t 出版时间 \t ISBN码 \t 价格\n"); _ui();
                        current = head;
                        for (current = current->next; current != NULL; current = current->next)
                        {
                                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();
                                current = current->next;
                        }
                }
                system("pause");
}
void _inquire(const library *head) //(3)查询
{
        char choice, select[30];
        const library *current=head;
        _ui(); printf("\t\t|\t\t图书信息管理系统:查询\t\t|\n"); _ui();//书名或作者名查询
        printf("Y:默认书名查询,N:作者名查询,回车返回菜单(Y/N):");
        while (ch_gets(&choice, 1) != NULL&& choice != '\0')
        {
                if (choice == 'Y' || choice == 'y')
                {
                        puts("输入书名:");
                        ch_gets(select, 30);
                        current = _search(current,select,1);
                        if (current != NULL) //能找找到匹配项时 
                             {BROWSE; system("pause");}
                        else
                        {puts("没有结果"); system("pause");}
                }
                else if (choice == 'N' || choice == 'n')
                {
                        puts("输入作者名:");
                        ch_gets(select, 30);
                        current = _search(current,select,2);
                        if (current!=NULL)
                             {BROWSE; system("pause");}
                        else
                        {puts("没有结果"); system("pause");}
                }
                else
                        puts("你输入有误,请再输入:");
        }
}
library * _sorting(library *head) //(4)排序
{
        char choice;
        library *current= head->next, *prev= head, *temp=NULL;
        if ((temp = (struct book *)malloc(sizeof(library))) == NULL)
             {puts("无法分配内存..."); system("pause"); return NULL;}
        _ui(); printf("\t\t|\t\t图书信息管理系统:排序\t\t|\n"); _ui();//书名或价格排序
        printf("Y:默认书名排列,N:价格排列,回车返回菜单(Y/N):");
        while (ch_gets(&choice, 1) != NULL && choice != '\0')
        {
                if (choice == 'Y' || choice == 'y')//书名排序
                {
                        for (; strcmp(prev->book_name, current->book_name)>0 || current != NULL; current = current->next)
                        {
                                temp = prev;
                                prev = current->next;
                                current->next = temp;
                        }
                        _browse(head);
                }
                else if (choice == 'N' || choice == 'n')//价格排序
                {
                        printf("Y:从大到小排列,N:从小到大排列,回车返回菜单(Y/N):");
                        while (ch_gets(&choice, 1) != NULL&& choice != '\0')
                        {
                                if (choice == 'Y' || choice == 'y')//从大到小
                                {
                                        for (; prev->price > current->price || current != NULL; current = current->next)
                                        {
                                                temp = prev;
                                                prev = current->next;
                                                current->next = temp;
                                        }
                                        _browse(head);
                                }
                                else if (choice == 'N' || choice == 'n') //从小到大
                                {
                                        for (; prev->price > current->price|| current != NULL; current = current->next)
                                        {
                                                temp = current->next;
                                                current->next = prev;
                                                prev = temp;
                                                free(temp);
                                        }
                                        _browse(head);
                                }
                        }
                }
                else
                {
                        puts("你输入有误,请再输入:");
                        scanf("%c", &choice);
                }
        }
        free(temp);
        return head;
}
library * menu_modify(library *current) //用于下面”_delete_modify“函数的删除与修改的选项菜单以及其功能实现
{
        char choice;
        _ui(); printf("\t\t|\t\t图书信息管理系统:删除与修改(操作菜单)\t|\n"); _ui();
        printf("\t\t|(1)书名\t\t(2)作者\t\t|\n"); _ui();
        printf("\t\t|(3)归属分类 \t\t(4)出版社\t\t|\n"); _ui();
        printf("\t\t|(5)出版时间 \t\t(6)ISBN码\t\t|\n"); _ui();
        printf("\t\t|(7)价格  \t\t(8)删除此条记录\t|\n"); _ui();
        puts("选择的操作数据的选项(回车取消操作,返回上一层):\n");
        while (ch_gets(&choice, 1) != NULL&& choice != '\0')
        {
                switch (choice) {
                case 1:
                        puts("输入你修改的书名:");
                        ch_gets(current->book_name, 20); break;
                case 2:
                        puts("输入你修改的作者:");
                        ch_gets(current->author, 20); break;
                case 3:
                        puts("输入你修改的归属分类:");
                        ch_gets(current->classification, 20); break;
                case 4:
                        puts("输入你修改的出版社:");
                        ch_gets(current->press, 30); break;
                case 5:
                        puts("输入你修改的出版时间:");
                        ch_gets(current->publish_time, 5); break;
                case 6:
                        puts("输入你修改的ISBN码:");
                        ch_gets(current->ISBN, 5); break;
                case 7:
                        puts("输入你修改的价格:");
                        scanf("%lf", ¤t->price); while (getchar() != '\n') continue; break;
                case 8:current = current->next; return NULL; break;
                }
        }
                return current;
}
library * _delete_modify(library *head) //(5)删除与修改
{
        library *current=head;
        char temp_input[30];
        _ui(); printf("\t\t|\t\t图书信息管理系统:删除与修改\t|\n"); _ui();
        printf("\t\t默认匹配修改,回车返回主菜单\n");
        printf("输入书名或ISBN码:");
        while (ch_gets(temp_input, 30) != NULL&& temp_input[0] != '\0')
        {
                        current = _search(current,temp_input,1); //使用书名查找
                        current = _search(current, temp_input,3); //使用ISBN码查找
                        if(current!=NULL)
                        {
                                BROWSE;
                                _ui(); current=menu_modify(current);
                                if(current!=NULL)   //删除时不显示修改后结果
                                BROWSE;
                                system("pause");
                        }
                        else
                                puts("你输入有误,请再输入:");
        }
        return head;
}
library * open_file() //打开文件,参考修改
{
        FILE *fbook;
        library *prev,*current,*head;
        if (access("book_mg.txt", 0)==0) //判断文件是否存在,存在返回零
                fbook = fopen("book_mg.dat", "rb");
        else 
        {
                fbook = fopen("book_mg.dat", "a");
                fclose(fbook); puts("创建book_mg.dat成功");
                fbook = fopen("book_mg.dat", "rb");
        }
        if ((head = current = prev = (library *)malloc(sizeof(library))) == NULL)    //使三个指针的地址相同,首地址head确定
             {puts("无法分配内存..."); system("pause"); return NULL;}
        else
                head->price=0; //类似的再次确定内存可访问;随意让首地址确定下来,觉得返回NULL不好。并将其中的成员赋值,原因是因为如果文件没内容时,head指针跟空了似的,好像把初始出来的内存垃圾值给其成员
        if (fbook == '\0') //判断文件是否有内容
        {
                fclose(fbook);
        }
        else
        {
                while (!feof(fbook)) //返回非零值代表已到达文件尾.说明零值时文件还有数据可输入
                {
                        if ((current = (library *)malloc(sizeof(library))) == NULL)
                              {puts("无法分配内存..."); system("pause"); return NULL;}
                        fread(current, sizeof(library), 1, fbook); //二进制读取,因为书的价格是double类型,为不丢失精度
                        //fscanf(fbook,"%s %s %s %s %s %s %lf", current->book_name, current->author, current->classification, current->press, current->publish_time, current->ISBN, ¤t->price); //文本模式读取
                        prev->next = current;    //因为prev在上面确定首地址时已经把prev地址指向head,第一次运行说明第一个current指向head->head
                        prev = current;            //为下次输入进行保留本次地址
                }
                prev->next = NULL;//最后完成输入的节点需要最后的指针指空,不然会变野指针
                fclose(fbook);
        }
        return head;
}

void  _save(library *head) //(7)存储
{
        FILE *fbook;
        library *prev = head;
        _ui(); printf("\t\t|\t图书信息管理系统:保存到文件\t\t|\n"); _ui();
        if ((fbook = fopen("book_mg.txt", "wb")) == NULL)
        {puts("文件不能打开...");return;}
        if (head->next != NULL)  //说明还有节点可以输入保存到文件里
        {
                for (prev=prev->next; prev != NULL; prev = prev->next)   //最开始prev指向了head,而由于打开文件时初始化的head是没有用的,所以prev=prev->next;舍弃第一个节点从第二个开始存
                        fwrite(prev, sizeof(library), 1, fbook);  //二进制保存
                        //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);  //保存
        }
        fclose(fbook);
        puts("保存完毕..."); system("pause");
}

int main(void)  //
{
        int choice=-1;
        library * book_head=open_file(); //初始化,并给首地址
        while (1)
        {
                system("cls");
                main_menu();
                if (scanf("%d", &choice)) //选项选择,带纠错
                {
                        if ((choice > 1 && 7 < choice))
                                printf("你的输入有误,请再输入:");
                }
                system("cls");
                while (getchar() != '\n') //防止'\n'
                        continue;
                switch (choice) {
                case 1:book_head=_entry(book_head);break;      //(1)录入

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

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

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

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

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

                case 7:free(book_head);
                        exit(0); 
                }
        }
        return 0;
}
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

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

使用道具 举报

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

本版积分规则

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

GMT+8, 2024-11-28 04:44

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

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