C2065和C2223的错误一直解决不了


#include<stdio.h>
#include<stdlib.h>
#include<string.h>



//图书信息
struct bookInfo
{
    char name[20];//书名
    char writter[100];//作者
    char publisher[100];//出版社
    int price; //价格
    int num; //数量
    char introduction[100];//简介
};

struct Node //Node节点
{
    struct bookInfo data; //链表里存的struct bookInfo类型
    struct Node* next;
};

struct Node* list = NULL; //更改为全局的列表为空,然后在主函数那初始化

//创建表头:表头就是一个结构体变量
struct Node* createHead()
{
    /*动态内存申请
    sizeof(struct node)就是求 struct node 这个结构体占用的字节数。
    malloc(sizeof(struct node))申请 struct node 这个结构体占用字节数大小的空间
    (struct node *) malloc(sizeof(struct node))将申请的空间的地址强制转化为 struct node * 指针类型
    headNade=(struct node *) malloc(sizeof(struct node))将那个强制转化的地址赋值给 headNade.
     */
    struct Node* headNode=(struct Node*)malloc(sizeof(struct Node));

    //变量的基本规则:使用前必须初始化,在这里只需要给next指针初始化,表头不需要存储数据,所以不用初始化
    headNode->next=NULL; //表头不存数据
    return headNode; //返回创建链表的头指针
};


//创建节点,为插入做准备
//用户的数据变为结构体的变量
struct Node* createNode(struct bookInfo data)
{
    struct Node* newNode=(struct Node*)malloc(sizeof(struct Node));
    newNode->data=data;
    newNode->next=NULL;
    return newNode;
};



//插入,表头法插入
void insertNodeByHead(struct Node* headNode,struct bookInfo data)
{
    struct Node* newNode=createNode(data);    //通过调用子函数,创建结点
    //必须先连接,后断开
    newNode->next=headNode->next;      //头插法,headnode->next为下一个结点(表头下一个结点)的地址,newnode的指针域指向下一个结点(地址)
    headNode->next=newNode;     // 原表头指向新建的结点(地址)
}

//指定位置删除
//posLeftNode->next=posNode->next;相邻指针
//free(posNode);指定删除的代码,删除完后要把posNode=NULL
void deleteNodeByName(struct Node* headNode,char *bookName) //通过书籍名字进行删除
{
    /*需要两个指针进行删除,先删除节点指针的Left左边,其次再删除节点指针的右边,一前一后*/
    struct Node* posLeftNode=headNode;
    struct Node* posNode=headNode->next;
    /*书籍名字是字符串,所以要使用字符串比较函数处理
    当我们删除节点不等于空,
    并且使用strcmp()比较,
    使用posNode->data.name和我们传过来的参数bookName进行比较*/
    while(posNode!=NULL&&strcmp(posNode->data.name,bookName)) 
    {
    /*让节点并排往下走*/
        posLeftNode=posNode;
        posNode=posLeftNode->next;
    }

    //讨论查找结果,如果posNode为空,那就是没有找到,无法删除,找到就删除
    if(posNode==NULL)
        return;
    else
    {
        printf("删除成功!\n");
        posLeftNode->next=posNode->next;
        free(posNode);
        posNode=NULL;
    }
}

//添加链表的查找函数,把找到的节点给它返回
struct Node* searchByName(struct Node* headNode,char *bookName)
{
    //只需要找到那个节点即可,不需要两个指针
    struct Node* posNode = headNode->next;
    while(posNode!=NULL&&strcmp(posNode->data.name,bookName)) //strcmp()比较括号里面的,如果相等,就退出循环,如果不等,那就执行循环
    {
        posNode=posNode->next;
    }
    return posNode;
}


//打印链表
void printList(struct Node* headNode)
{
    /*定义一个移动的指针pMove从第二个节点headNode->next开始打印*/
    struct Node* pMove=headNode->next;
    printf("书名\t作者\t出版社\t价格\t数量\t简介\n"); //表头
    while(pMove != NULL) // pMove不等于空的时候,打印节点的数据
    {
        //剥洋葱,一层一层
        printf("%s\t%s\t%s\t%d\t%d\t%s\n",pMove->data.name,pMove->data.writter,pMove->data.publisher,pMove->data.price,pMove->data.num,pMove->data.introduction); //让pMove往下一个节点走
        pMove=pMove->next;
    }
}

void makeMenu()//界面菜单
{
    printf("欢迎使用图书管理信息系统\n");
    printf("1.登记书籍信息\n");
    printf("2.浏览书籍查询\n"); 
    printf("3.借阅书籍\n");
    printf("4.归还书籍\n");
    printf("5.删除书籍\n");
    printf("6.查找书籍\n");
    printf("0.退出系统\n\n");
    printf("请选择您想使用的功能0-8:");
}

//文件存操作
void saveInfoToFile(const char *fileName,struct Node* headNode) //将链表里的信息打印到文件里去
{
    FILE *fp=fopen(fileName,"w"); //第一个指针使用写的方式打开文件
    struct Node* pMove=headNode->next;
    //当第二个节点不等于空时,就将链表里的信息打印到文件里去
    while(pMove) 
    {
        fprintf(fp,"%s\t%s\t%s\t%d\t%d\t%s\n",pMove->data.name,pMove->data.writter,pMove->data.publisher,pMove->data.price,pMove->data.num,pMove->data.introduction); //打印到指针文件指向的文件,打印的是pMove
        pMove=pMove->next;
    }

    fclose(fp); //关闭文件
}

//文件读操作
void readInfoFromFile(const char* fileName,struct Node* headNode)  //需要从文件里将内容读出
{
    //把文件当作是一个输入键盘,定义临时变量tempData,把数据读到变量(如:%s)里
    struct bookInfo tempData;

    FILE* fp=fopen(fileName,"r"); //第一个指针使用读的方式打开文件

    /*文件开始的时候是不存在的,不存在的时候,使用创建(w+)的读写方式打开文件*/
    if(fp==NULL)
    {
        fp=fopen(fileName,"w+");
    }

    while(fscanf(fp,"%s\t%s\t%s\t%d\t%d\t%s\n",pMove->data.name,pMove->data.writter,pMove->data.publisher,pMove->data.price,pMove->data.num,pMove->data.introduction)!=EOF) //加上" != EOF"后该程序就不是死循环了
    {

        /*做链表的插入,读一个信息就插入到链表中*/
        insertNodeByHead(list,tempData);
    }

    fclose(fp); //关闭文件
}



//按键处理,做交互
void keyDown()
{
    int userKey=0;
    //准备一个临时变量去存放书籍的临时信息
    struct bookInfo tempBook;
    //写个临时的指针用于查询
    struct Node* result=NULL;
    scanf("%d",&userKey);
    switch (userKey)
    {
    case 0:
        printf("\n-----退出-----\n");
        printf("退出成功\n");
        system("pause"); //防止闪屏
        exit(0); //关闭掉整个程序
        break;
    case 1:
        printf("\n-----登记-----\n");
        printf("书名:");
        scanf("%s",tempBook.name);
        printf("作者:");
        scanf("%s",tempBook.writter);
        printf("出版社:");
        scanf("%s",tempBook.publisher);
        printf("价格/元:");
        scanf("%d",&tempBook.price);
        printf("数量:");
        scanf("%d",&tempBook.num);
        printf("简介(<100字):");
        scanf("%s",tempBook.introduction);
        //scanf("%s%f%d",tempBook.name,&tempBook.price,&tempBook.num); //tempBook.name不需要加&取地址,因为是字符串
        insertNodeByHead(list, tempBook); // 插入链表
        saveInfoToFile("bookinfo.txt",list); //当做了数据修改,就将信息保存到bookinfo.txt文件中,读到链表中
        break;
    case 2:
        printf("\n-----浏览-----\n");
        printList(list); //打印链表
        break;
    case 3:
        printf("\n-----借阅-----\n"); //是把书的数量减少,书籍存在可以借,书的数量-1,不存在则提示借书失败
        //通过书籍名去借阅
        printf("请输入需要借阅的书名:");
        scanf("%s",tempBook.name);
        result=searchByName(list,tempBook.name);
            if(result==NULL)
        {
            printf("没有此书籍,无法借阅!");
        }
        else
        {
            if(result->data.num>0) //大于0说明有书籍可借阅
            {
                result->data.num--; //书的数量-1
                printf("借阅成功");
            }
            else
            {
                printf("当前书籍无库存,借阅失败");
            }
        }
        break;
    case 4:
        printf("\n-----归还-----\n"); //是把当前书的数量增加+1
            printf("请输入需要归还的书名:");
        scanf("%s",tempBook.name);
        result=searchByName(list,tempBook.name);
            if(result==NULL)
        {
            printf("没有此书籍借阅记录,无法归还");
        }
        else
        {
                result->data.num++; //书的数量+1
                printf("归还成功");
        }
        break;
    case 5:
        printf("\n-----删除-----\n");
        printf("请输入要删除书籍的名字:");
        scanf("%s",tempBook.name);
        deleteNodeByName(list,tempBook.name);
        saveInfoToFile("bookinfo.txt",list); //删除之后需要同步到文件,因为涉及到数据的修改
        break;
    case 6:
        printf("\n-----查找-----\n");
        printf("请输入要查询书籍的名字:");
        scanf("%s",tempBook.name);
        result=searchByName(list,tempBook.name);
        //查找等效于链表的查找
        //判断如果result等于NULL,就表示未找到
        if(result==NULL)
        {
            printf("未找到该书籍");
        }
        else
        {
            printf("书名\t价格\t数量\n");
            printf("%s\t%s\t%s\t%d\t%d\t%s\n",pMove->data.name,pMove->data.writter,pMove->data.publisher,pMove->data.price,pMove->data.num,pMove->data.introduction);
        }
        break;
    default:
        printf("\n-----错误-----\n"); //在switch语句中,如果表达式的值与每一中情况都不同,则执行default:后面的语句
        break;

    }
}



//调用测试实现
int main()
{
    list=createHead();
    readInfoFromFile("bookinfo.txt",list); //当系统运行的时候,就将文件的东西读到列表里

    /*while(1)其中1代表一个常量表达式,
    它永远不会等于0。循环会一直执行下去。
    除非你设置break等类似的跳出循环语句循环才会中止。*/
    while(1)
    {
        makeMenu();
        keyDown();
        system("pause");
        system("cls"); //清屏代码:
    }

    system("pause"); //就是暂停程序的执行,等待任意健继续执行。
    return 0;
}

img

这报错不是已经很清楚了?pMove未定义,你上面的其他函数用pMove都有定义的。

pMove未定义,使用前需要先定义

修改完善如下,供参考:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
//图书信息
struct bookInfo
{
    char name[20];//书名
    char writter[100];//作者
    char publisher[100];//出版社
    int  price; //价格
    int  num; //数量
    char introduction[100];//简介
};
 
struct Node //Node节点
{
    struct bookInfo data; //链表里存的struct bookInfo类型
    struct Node* next;
};
 
struct Node* list = NULL; //更改为全局的列表为空,然后在主函数那初始化
 
//创建表头:表头就是一个结构体变量
struct Node* createHead()
{
    /*动态内存申请
    sizeof(struct node)就是求 struct node 这个结构体占用的字节数。
    malloc(sizeof(struct node))申请 struct node 这个结构体占用字节数大小的空间
    (struct node *) malloc(sizeof(struct node))将申请的空间的地址强制转化为 struct node * 指针类型
    headNade=(struct node *) malloc(sizeof(struct node))将那个强制转化的地址赋值给 headNade.
     */
    struct Node* headNode=(struct Node*)malloc(sizeof(struct Node));
 
    //变量的基本规则:使用前必须初始化,在这里只需要给next指针初始化,表头不需要存储数据,所以不用初始化
    headNode->next=NULL; //表头不存数据
    return headNode; //返回创建链表的头指针
};

//创建节点,为插入做准备
//用户的数据变为结构体的变量
struct Node* createNode(struct bookInfo data)
{
    struct Node* newNode=(struct Node*)malloc(sizeof(struct Node));
    newNode->data=data;
    newNode->next=NULL;
    return newNode;
};
 
//插入,表头法插入
void insertNodeByHead(struct Node* headNode,struct bookInfo data)
{
    struct Node* newNode=createNode(data);    //通过调用子函数,创建结点
    //必须先连接,后断开
    newNode->next=headNode->next;
    //头插法,headnode->next为下一个结点(表头下一个结点)的地址,newnode的指针域指向下一个结点(地址)
    headNode->next=newNode;
    // 原表头指向新建的结点(地址)
}
 
//指定位置删除
//posLeftNode->next=posNode->next;相邻指针
//free(posNode);指定删除的代码,删除完后要把posNode=NULL
void deleteNodeByName(struct Node* headNode,char *bookName) //通过书籍名字进行删除
{
    /*需要两个指针进行删除,先删除节点指针的Left左边,其次再删除节点指针的右边,一前一后*/
    struct Node* posLeftNode=headNode;
    struct Node* posNode=headNode->next;
    /*书籍名字是字符串,所以要使用字符串比较函数处理
    当我们删除节点不等于空,
    并且使用strcmp()比较,
    使用posNode->data.name和我们传过来的参数bookName进行比较*/
    while(posNode!=NULL&&strcmp(posNode->data.name,bookName)) 
    {
    /*让节点并排往下走*/
        posLeftNode=posNode;
        posNode=posLeftNode->next;
    }
 
    //讨论查找结果,如果posNode为空,那就是没有找到,无法删除,找到就删除
    if(posNode==NULL)
        return;
    else
    {
        printf("删除成功!\n");
        posLeftNode->next=posNode->next;
        free(posNode);
        posNode=NULL;
    }
}
 
//添加链表的查找函数,把找到的节点给它返回
struct Node* searchByName(struct Node* headNode,char *bookName)
{
    //只需要找到那个节点即可,不需要两个指针
    struct Node* posNode = headNode->next;
    while(posNode!=NULL && strcmp(posNode->data.name,bookName))
    //strcmp()比较括号里面的,如果相等,就退出循环,如果不等,那就执行循环
    {
        posNode=posNode->next;
    }
    return posNode;
}
 
 
//打印链表
void printList(struct Node* headNode)
{
    /*定义一个移动的指针pMove从第二个节点headNode->next开始打印*/
    struct Node* pMove=headNode->next;
    printf("书名\t作者\t出版社\t价格\t数量\t简介\n"); //表头
    while(pMove != NULL) // pMove不等于空的时候,打印节点的数据
    {
        //剥洋葱,一层一层
        printf("%s\t%s\t%s\t%d\t%d\t%s\n",pMove->data.name,pMove->data.writter,
             pMove->data.publisher,pMove->data.price,pMove->data.num,pMove->data.introduction);
             //让pMove往下一个节点走
        pMove=pMove->next;
    }
}
 
void makeMenu()//界面菜单
{
    printf("欢迎使用图书管理信息系统\n");
    printf("1.登记书籍信息\n");
    printf("2.浏览书籍查询\n"); 
    printf("3.借阅书籍\n");
    printf("4.归还书籍\n");
    printf("5.删除书籍\n");
    printf("6.查找书籍\n");
    printf("0.退出系统\n\n");
    printf("请选择您想使用的功能0-8:");
}
 
//文件存操作
void saveInfoToFile(const char *fileName,struct Node* headNode) //将链表里的信息打印到文件里去
{
    FILE *fp=fopen(fileName,"w"); //第一个指针使用写的方式打开文件
    struct Node* pMove=headNode->next;
    //当第二个节点不等于空时,就将链表里的信息打印到文件里去
    while(pMove) 
    {
        fprintf(fp,"%s\t%s\t%s\t%d\t%d\t%s\n",pMove->data.name,pMove->data.writter,
             pMove->data.publisher,pMove->data.price,pMove->data.num,pMove->data.introduction); //打印到指针文件指向的文件,打印的是pMove
        pMove=pMove->next;
    }
    fclose(fp); //关闭文件
}
 
//文件读操作
void readInfoFromFile(const char* fileName,struct Node* headNode)  //需要从文件里将内容读出
{
    //把文件当作是一个输入键盘,定义临时变量tempData,把数据读到变量(如:%s)里
    struct bookInfo tempData;
 
    FILE* fp=fopen(fileName,"r"); //第一个指针使用读的方式打开文件
 
    /*文件开始的时候是不存在的,不存在的时候,使用创建(w+)的读写方式打开文件*/
    if(fp==NULL)
    {
        fp=fopen(fileName,"w+");
    }
 
    //while(fscanf(fp,"%s\t%s\t%s\t%d\t%d\t%s\n",pMove->data.name,pMove->data.writter, 修改
    //    pMove->data.publisher,pMove->data.price,pMove->data.num,pMove->data.introduction)!=EOF) //加上" != EOF"后该程序就不是死循环了
    while (1)
    {
        if(fscanf(fp,"%s\t%s\t%s\t%d\t%d\t%s\n",tempData.name,tempData.writter,
               tempData.publisher,&tempData.price,&tempData.num,tempData.introduction) != 6) break;
        /*做链表的插入,读一个信息就插入到链表中*/
        insertNodeByHead(list,tempData);
    }
    fclose(fp); //关闭文件
}

//按键处理,做交互
void keyDown()
{
    int userKey=0;
    //准备一个临时变量去存放书籍的临时信息
    struct bookInfo tempBook;
    //写个临时的指针用于查询
    struct Node* result=NULL;
    scanf("%d",&userKey);
    switch (userKey)
    {
    case 0:
        printf("\n-----退出-----\n");
        printf("退出成功\n");
        system("pause"); //防止闪屏
        exit(0); //关闭掉整个程序
        break;
    case 1:
        printf("\n-----登记-----\n");
        printf("书名:");
        scanf("%s",tempBook.name);
        getchar();
        printf("作者:");
        scanf("%s",tempBook.writter);
        getchar();
        printf("出版社:");
        scanf("%s",tempBook.publisher);
        getchar();
        printf("价格(整数:元):");
        scanf("%d",&tempBook.price);
        getchar();
        printf("数量(整数):");
        scanf("%d",&tempBook.num);
        getchar();
        printf("简介(<100字):");
        gets(tempBook.introduction); //scanf("%s",tempBook.introduction);  修改
        //scanf("%s%f%d",tempBook.name,&tempBook.price,&tempBook.num);
        //tempBook.name不需要加&取地址,因为是字符串
        insertNodeByHead(list, tempBook); // 插入链表
        saveInfoToFile("bookinfo.txt",list);
        //当做了数据修改,就将信息保存到bookinfo.txt文件中,读到链表中
        break;
    case 2:
        printf("\n-----浏览-----\n");
        printList(list); //打印链表
        break;
    case 3:
        printf("\n-----借阅-----\n");
        //是把书的数量减少,书籍存在可以借,书的数量-1,不存在则提示借书失败
        //通过书籍名去借阅
        printf("请输入需要借阅的书名:");
        scanf("%s",tempBook.name);
        getchar();
        result=searchByName(list,tempBook.name);
        if(result==NULL)
        {
            printf("没有此书籍,无法借阅!");
        }
        else
        {
            if(result->data.num>0) //大于0说明有书籍可借阅
            {
                result->data.num--; //书的数量-1
                printf("借阅成功");
            }
            else
            {
                printf("当前书籍无库存,借阅失败");
            }
        }
        break;
    case 4:
        printf("\n-----归还-----\n"); //是把当前书的数量增加+1
        printf("请输入需要归还的书名:");
        scanf("%s",tempBook.name);
        getchar();
        result=searchByName(list,tempBook.name);
            if(result==NULL)
        {
            printf("没有此书籍借阅记录,无法归还\n");
        }
        else
        {
                result->data.num++; //书的数量+1
                printf("归还成功");
        }
        break;
    case 5:
        printf("\n-----删除-----\n");
        printf("请输入要删除书籍的名字:");
        scanf("%s",tempBook.name);
        getchar();
        deleteNodeByName(list,tempBook.name);
        saveInfoToFile("bookinfo.txt",list);
        //删除之后需要同步到文件,因为涉及到数据的修改
        break;
    case 6:
        printf("\n-----查找-----\n");
        printf("请输入要查询书籍的名字:");
        scanf("%s",tempBook.name);
        getchar();
        result=searchByName(list,tempBook.name);
        //查找等效于链表的查找
        //判断如果result等于NULL,就表示未找到
        if(result==NULL)
        {
            printf("未找到该书籍\n");
        }
        else
        {
            printf("书名\t作者\t出版社\t价格\t数量\t简介\n");
            //printf("%s\t%s\t%s\t%d\t%d\t%s\n",pMove->data.name,pMove->data.writter,   修改
            //     pMove->data.publisher,pMove->data.price,pMove->data.num,pMove->data.introduction);
            printf("%s\t%s\t%s\t%d\t%d\t%s\n",result->data.name,result->data.writter,
                 result->data.publisher,result->data.price,result->data.num,result->data.introduction);
        }
        break;
    default:
        printf("\n-----错误-----\n");
        //在switch语句中,如果表达式的值与每一中情况都不同,则执行default:后面的语句
        break;
 
    }
}

//调用测试实现
int main()
{
    list=createHead();
    readInfoFromFile("bookinfo.txt",list); //当系统运行的时候,就将文件的东西读到列表里
 
    //while(1)其中1代表一个常量表达式,
    //它永远不会等于0。循环会一直执行下去。
    //除非你设置break等类似的跳出循环语句循环才会中止。
    while(1)
    {
        makeMenu();
        keyDown();
        system("pause");
        system("cls"); //清屏代码:
    }
    system("pause"); //就是暂停程序的执行,等待任意健继续执行。
    return 0;
}

修改1:

readInfoFromFile函数中

img

//文件读操作
void readInfoFromFile(const char* fileName,struct Node* headNode)  //需要从文件里将内容读出
{
    //把文件当作是一个输入键盘,定义临时变量tempData,把数据读到变量(如:%s)里
    struct bookInfo tempData;
   
 
    FILE* fp=fopen(fileName,"r"); //第一个指针使用读的方式打开文件
 
    /*文件开始的时候是不存在的,不存在的时候,使用创建(w+)的读写方式打开文件*/
    if(fp==NULL)
    {
        fp=fopen(fileName,"w+");
    }
 
    while(fscanf(fp,"%s\t%s\t%s\t%d\t%d\t%s\n",tempData.name,tempData.writter,tempData.publisher,tempData.price,tempData.num,tempData.introduction)!=EOF) //加上" != EOF"后该程序就不是死循环了
    {
 
        /*做链表的插入,读一个信息就插入到链表中*/
        insertNodeByHead(list,tempData);
    }
 
    fclose(fp); //关闭文件
}
 

修改2

keyDown() 函数的case 6:

img

//按键处理,做交互
void keyDown()
{
    int userKey=0;
    //准备一个临时变量去存放书籍的临时信息
    struct bookInfo tempBook;
    //写个临时的指针用于查询
    struct Node* result=NULL;
    scanf("%d",&userKey);
    switch (userKey)
    {
    case 0:
        printf("\n-----退出-----\n");
        printf("退出成功\n");
        system("pause"); //防止闪屏
        exit(0); //关闭掉整个程序
        break;
    case 1:
        printf("\n-----登记-----\n");
        printf("书名:");
        scanf("%s",tempBook.name);
        printf("作者:");
        scanf("%s",tempBook.writter);
        printf("出版社:");
        scanf("%s",tempBook.publisher);
        printf("价格/元:");
        scanf("%d",&tempBook.price);
        printf("数量:");
        scanf("%d",&tempBook.num);
        printf("简介(<100字):");
        scanf("%s",tempBook.introduction);
        //scanf("%s%f%d",tempBook.name,&tempBook.price,&tempBook.num); //tempBook.name不需要加&取地址,因为是字符串
        insertNodeByHead(list, tempBook); // 插入链表
        saveInfoToFile("bookinfo.txt",list); //当做了数据修改,就将信息保存到bookinfo.txt文件中,读到链表中
        break;
    case 2:
        printf("\n-----浏览-----\n");
        printList(list); //打印链表
        break;
    case 3:
        printf("\n-----借阅-----\n"); //是把书的数量减少,书籍存在可以借,书的数量-1,不存在则提示借书失败
        //通过书籍名去借阅
        printf("请输入需要借阅的书名:");
        scanf("%s",tempBook.name);
        result=searchByName(list,tempBook.name);
            if(result==NULL)
        {
            printf("没有此书籍,无法借阅!");
        }
        else
        {
            if(result->data.num>0) //大于0说明有书籍可借阅
            {
                result->data.num--; //书的数量-1
                printf("借阅成功");
            }
            else
            {
                printf("当前书籍无库存,借阅失败");
            }
        }
        break;
    case 4:
        printf("\n-----归还-----\n"); //是把当前书的数量增加+1
            printf("请输入需要归还的书名:");
        scanf("%s",tempBook.name);
        result=searchByName(list,tempBook.name);
            if(result==NULL)
        {
            printf("没有此书籍借阅记录,无法归还");
        }
        else
        {
                result->data.num++; //书的数量+1
                printf("归还成功");
        }
        break;
    case 5:
        printf("\n-----删除-----\n");
        printf("请输入要删除书籍的名字:");
        scanf("%s",tempBook.name);
        deleteNodeByName(list,tempBook.name);
        saveInfoToFile("bookinfo.txt",list); //删除之后需要同步到文件,因为涉及到数据的修改
        break;
    case 6:
        printf("\n-----查找-----\n");
        printf("请输入要查询书籍的名字:");
        scanf("%s",tempBook.name);
        result=searchByName(list,tempBook.name);
        //查找等效于链表的查找
        //判断如果result等于NULL,就表示未找到
        if(result==NULL)
        {
            printf("未找到该书籍");
        }
        else
        {
            printf("书名\t价格\t数量\n");
            printf("%s\t%s\t%s\t%d\t%d\t%s\n",result->data.name,result->data.writter,result->data.publisher,result->data.price,result->data.num,result->data.introduction);
        }
        break;
    default:
        printf("\n-----错误-----\n"); //在switch语句中,如果表达式的值与每一中情况都不同,则执行default:后面的语句
        break;
 
    }
}

修改后的完整程序

 
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
 
 
 
//图书信息
struct bookInfo
{
    char name[20];//书名
    char writter[100];//作者
    char publisher[100];//出版社
    int price; //价格
    int num; //数量
    char introduction[100];//简介
};
 
struct Node //Node节点
{
    struct bookInfo data; //链表里存的struct bookInfo类型
    struct Node* next;
};
 
struct Node* list = NULL; //更改为全局的列表为空,然后在主函数那初始化
 
//创建表头:表头就是一个结构体变量
struct Node* createHead()
{
    /*动态内存申请
    sizeof(struct node)就是求 struct node 这个结构体占用的字节数。
    malloc(sizeof(struct node))申请 struct node 这个结构体占用字节数大小的空间
    (struct node *) malloc(sizeof(struct node))将申请的空间的地址强制转化为 struct node * 指针类型
    headNade=(struct node *) malloc(sizeof(struct node))将那个强制转化的地址赋值给 headNade.
     */
    struct Node* headNode=(struct Node*)malloc(sizeof(struct Node));
 
    //变量的基本规则:使用前必须初始化,在这里只需要给next指针初始化,表头不需要存储数据,所以不用初始化
    headNode->next=NULL; //表头不存数据
    return headNode; //返回创建链表的头指针
};
 
 
//创建节点,为插入做准备
//用户的数据变为结构体的变量
struct Node* createNode(struct bookInfo data)
{
    struct Node* newNode=(struct Node*)malloc(sizeof(struct Node));
    newNode->data=data;
    newNode->next=NULL;
    return newNode;
};
 
 
 
//插入,表头法插入
void insertNodeByHead(struct Node* headNode,struct bookInfo data)
{
    struct Node* newNode=createNode(data);    //通过调用子函数,创建结点
    //必须先连接,后断开
    newNode->next=headNode->next;      //头插法,headnode->next为下一个结点(表头下一个结点)的地址,newnode的指针域指向下一个结点(地址)
    headNode->next=newNode;     // 原表头指向新建的结点(地址)
}
 
//指定位置删除
//posLeftNode->next=posNode->next;相邻指针
//free(posNode);指定删除的代码,删除完后要把posNode=NULL
void deleteNodeByName(struct Node* headNode,char *bookName) //通过书籍名字进行删除
{
    /*需要两个指针进行删除,先删除节点指针的Left左边,其次再删除节点指针的右边,一前一后*/
    struct Node* posLeftNode=headNode;
    struct Node* posNode=headNode->next;
    /*书籍名字是字符串,所以要使用字符串比较函数处理
    当我们删除节点不等于空,
    并且使用strcmp()比较,
    使用posNode->data.name和我们传过来的参数bookName进行比较*/
    while(posNode!=NULL&&strcmp(posNode->data.name,bookName)) 
    {
    /*让节点并排往下走*/
        posLeftNode=posNode;
        posNode=posLeftNode->next;
    }
 
    //讨论查找结果,如果posNode为空,那就是没有找到,无法删除,找到就删除
    if(posNode==NULL)
        return;
    else
    {
        printf("删除成功!\n");
        posLeftNode->next=posNode->next;
        free(posNode);
        posNode=NULL;
    }
}
 
//添加链表的查找函数,把找到的节点给它返回
struct Node* searchByName(struct Node* headNode,char *bookName)
{
    //只需要找到那个节点即可,不需要两个指针
    struct Node* posNode = headNode->next;
    while(posNode!=NULL&&strcmp(posNode->data.name,bookName)) //strcmp()比较括号里面的,如果相等,就退出循环,如果不等,那就执行循环
    {
        posNode=posNode->next;
    }
    return posNode;
}
 
 
//打印链表
void printList(struct Node* headNode)
{
    /*定义一个移动的指针pMove从第二个节点headNode->next开始打印*/
    struct Node* pMove=headNode->next;
    printf("书名\t作者\t出版社\t价格\t数量\t简介\n"); //表头
    while(pMove != NULL) // pMove不等于空的时候,打印节点的数据
    {
        //剥洋葱,一层一层
        printf("%s\t%s\t%s\t%d\t%d\t%s\n",pMove->data.name,pMove->data.writter,pMove->data.publisher,pMove->data.price,pMove->data.num,pMove->data.introduction); //让pMove往下一个节点走
        pMove=pMove->next;
    }
}
 
void makeMenu()//界面菜单
{
    printf("欢迎使用图书管理信息系统\n");
    printf("1.登记书籍信息\n");
    printf("2.浏览书籍查询\n"); 
    printf("3.借阅书籍\n");
    printf("4.归还书籍\n");
    printf("5.删除书籍\n");
    printf("6.查找书籍\n");
    printf("0.退出系统\n\n");
    printf("请选择您想使用的功能0-8:");
}
 
//文件存操作
void saveInfoToFile(const char *fileName,struct Node* headNode) //将链表里的信息打印到文件里去
{
    FILE *fp=fopen(fileName,"w"); //第一个指针使用写的方式打开文件
    struct Node* pMove=headNode->next;
    //当第二个节点不等于空时,就将链表里的信息打印到文件里去
    while(pMove) 
    {
        fprintf(fp,"%s\t%s\t%s\t%d\t%d\t%s\n",pMove->data.name,pMove->data.writter,pMove->data.publisher,pMove->data.price,pMove->data.num,pMove->data.introduction); //打印到指针文件指向的文件,打印的是pMove
        pMove=pMove->next;
    }
 
    fclose(fp); //关闭文件
}
 
//文件读操作
void readInfoFromFile(const char* fileName,struct Node* headNode)  //需要从文件里将内容读出
{
    //把文件当作是一个输入键盘,定义临时变量tempData,把数据读到变量(如:%s)里
    struct bookInfo tempData;
   
 
    FILE* fp=fopen(fileName,"r"); //第一个指针使用读的方式打开文件
 
    /*文件开始的时候是不存在的,不存在的时候,使用创建(w+)的读写方式打开文件*/
    if(fp==NULL)
    {
        fp=fopen(fileName,"w+");
    }
 
    while(fscanf(fp,"%s\t%s\t%s\t%d\t%d\t%s\n",tempData.name,tempData.writter,tempData.publisher,tempData.price,tempData.num,tempData.introduction)!=EOF) //加上" != EOF"后该程序就不是死循环了
    {
 
        /*做链表的插入,读一个信息就插入到链表中*/
        insertNodeByHead(list,tempData);
    }
 
    fclose(fp); //关闭文件
}
 
 
 
//按键处理,做交互
void keyDown()
{
    int userKey=0;
    //准备一个临时变量去存放书籍的临时信息
    struct bookInfo tempBook;
    //写个临时的指针用于查询
    struct Node* result=NULL;
    scanf("%d",&userKey);
    switch (userKey)
    {
    case 0:
        printf("\n-----退出-----\n");
        printf("退出成功\n");
        system("pause"); //防止闪屏
        exit(0); //关闭掉整个程序
        break;
    case 1:
        printf("\n-----登记-----\n");
        printf("书名:");
        scanf("%s",tempBook.name);
        printf("作者:");
        scanf("%s",tempBook.writter);
        printf("出版社:");
        scanf("%s",tempBook.publisher);
        printf("价格/元:");
        scanf("%d",&tempBook.price);
        printf("数量:");
        scanf("%d",&tempBook.num);
        printf("简介(<100字):");
        scanf("%s",tempBook.introduction);
        //scanf("%s%f%d",tempBook.name,&tempBook.price,&tempBook.num); //tempBook.name不需要加&取地址,因为是字符串
        insertNodeByHead(list, tempBook); // 插入链表
        saveInfoToFile("bookinfo.txt",list); //当做了数据修改,就将信息保存到bookinfo.txt文件中,读到链表中
        break;
    case 2:
        printf("\n-----浏览-----\n");
        printList(list); //打印链表
        break;
    case 3:
        printf("\n-----借阅-----\n"); //是把书的数量减少,书籍存在可以借,书的数量-1,不存在则提示借书失败
        //通过书籍名去借阅
        printf("请输入需要借阅的书名:");
        scanf("%s",tempBook.name);
        result=searchByName(list,tempBook.name);
            if(result==NULL)
        {
            printf("没有此书籍,无法借阅!");
        }
        else
        {
            if(result->data.num>0) //大于0说明有书籍可借阅
            {
                result->data.num--; //书的数量-1
                printf("借阅成功");
            }
            else
            {
                printf("当前书籍无库存,借阅失败");
            }
        }
        break;
    case 4:
        printf("\n-----归还-----\n"); //是把当前书的数量增加+1
            printf("请输入需要归还的书名:");
        scanf("%s",tempBook.name);
        result=searchByName(list,tempBook.name);
            if(result==NULL)
        {
            printf("没有此书籍借阅记录,无法归还");
        }
        else
        {
                result->data.num++; //书的数量+1
                printf("归还成功");
        }
        break;
    case 5:
        printf("\n-----删除-----\n");
        printf("请输入要删除书籍的名字:");
        scanf("%s",tempBook.name);
        deleteNodeByName(list,tempBook.name);
        saveInfoToFile("bookinfo.txt",list); //删除之后需要同步到文件,因为涉及到数据的修改
        break;
    case 6:
        printf("\n-----查找-----\n");
        printf("请输入要查询书籍的名字:");
        scanf("%s",tempBook.name);
        result=searchByName(list,tempBook.name);
        //查找等效于链表的查找
        //判断如果result等于NULL,就表示未找到
        if(result==NULL)
        {
            printf("未找到该书籍");
        }
        else
        {
            printf("书名\t价格\t数量\n");
            printf("%s\t%s\t%s\t%d\t%d\t%s\n",result->data.name,result->data.writter,result->data.publisher,result->data.price,result->data.num,result->data.introduction);
        }
        break;
    default:
        printf("\n-----错误-----\n"); //在switch语句中,如果表达式的值与每一中情况都不同,则执行default:后面的语句
        break;
 
    }
}
 
 
 
//调用测试实现
int main()
{
    list=createHead();
    readInfoFromFile("bookinfo.txt",list); //当系统运行的时候,就将文件的东西读到列表里
 
    /*while(1)其中1代表一个常量表达式,
    它永远不会等于0。循环会一直执行下去。
    除非你设置break等类似的跳出循环语句循环才会中止。*/
    while(1)
    {
        makeMenu();
        keyDown();
        system("pause");
        system("cls"); //清屏代码:
    }
 
    system("pause"); //就是暂停程序的执行,等待任意健继续执行。
    return 0;
}

在164行前面加上

struct Node* pMove= (struct Node*)malloc(sizeof(struct Node))