C/C++图书管理系统bug:对于查询图书信息这个功能有问题,n为链表长度,不知道为什么n始终为0,导致不执行for循环,也就是不会打印出图书的信息,想知道问题出在哪里,应该怎么改
void Print_book() /*查询图书信息*/
{
BK* p;
int i;
char e[10];
p = h_book;
printf("输入查询的图书编号:");
scanf("%s", e);
for (i = 0; i < n; i++)
{
if (strcmp(p->book_num, e) == 0)
{
printf("\n图书信息如下:\n\n");
printf("图书编号\t图书名称\t图书作者\t现有\t库存\n");
printf("%s\t\t%s\t\t%s\t\t%d\t%d\n", p->book_num, p->book_name, p->book_writer, p->book_xy, p->book_kc);
break;
}
else
p = p->next;
}
printf("\n图书信息打印完毕!按任意键继续下一步操作..");
_getch();
system("cls");
}
下面是全部代码
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include <string.h>
#include <stdlib.h>
#include<conio.h>
#define Max 4
typedef struct book
{
char book_num[10]; // 图书编号
char book_name[20]; // 图书名称
char book_writer[10]; // 图书作者
int book_xy; // 图书现有量
int book_kc; // 库存数量
int n; //链表长度
struct book* next;
}BK;
typedef struct borrow
{
char borrow_book_num[10];
char limit_date[10];
}BO;
typedef struct reader
{
char reader_num[10];
char reader_name[10];
int right;
int m; //链表长度
BO borrow[Max];
struct reader* next;
}RD;
BK* h_book;
RD* h_reader;
int n=0;
int m=0;
void Login();
int Menu();
void Init();
void Menu_select();
void Insert_New_Book();
void add_reader();
void Print_reader();
void Print_book();
void Borrow_Book();
void Return_Book();
void Save();
void Save_Book();
void Save_Reader();
void Load();
void Load_Reader();
void Load_Book();
void Login()
{
system("cls");
printf("\n\n\n\t\t***************************************\n");
printf("\n\n\n\t\t** 欢迎使用图书管理系统 **\n");
printf("\n\n\n\t\t***************************************\n");
printf("\n\n\n\t\t 按任意键进入系统...");
_getch();
system("cls");
}
int Menu() /*主菜单*/
{
int dm;
printf("\n\t\t图书管理系统主菜单\n");
printf("=================================================\n");
printf("*\t1----采编入库 \n");
printf("*\t2----登记读者 \n");
printf("*\t3----借阅登记 \n");
printf("*\t4----还书管理 \n");
printf("*\t5----查询图书信息 \n");
printf("*\t6----查询读者信息 \n");
printf("*\t0----退出系统 \n");
printf("=================================================\n");
printf("请选择相应的代码:");
for (;;)
{
scanf("%d", &dm); //dm输入的数字
if (dm < 0 || dm>7)
printf("\n错误!请重新输入:");
else
break;
}
return dm;
}
void Menu_select()/*主菜单选择函数*/
{
for (;;)
{
switch (Menu()) /*功能选择*/
{
case 0:
system("cls");
Save();
printf("\n\n\t文件保存成功!\n");
printf("\n\n\t欢迎下次使用本系统!\n");
_getch();
exit(0);
case 1: Insert_New_Book(); break;
case 2: add_reader(); break;
case 3: Borrow_Book(); break;
case 4: Return_Book(); break;
case 5: Print_book(); break;
case 6: Print_reader(); break;
default:printf("\n错误!");
exit(0);
}
}
}
/// <summary>
///
/// </summary>
void Init() /*初始化*/
{
BK* p0;
printf("\n图书初始化开始,请输入图书信息..\n包括编号.书名.数量..\n");
p0 = (BK*)malloc(sizeof(BK));
/*
malloc函数的原型为:void *malloc (unsigned int size)
其作用是在内存的动态存储区中分配一个长度为size的连续空间。
其参数是一个无符号整形数,
返回值是一个指向所分配的连续存储域的起始地址的指针。
*/
h_book = p0;
printf("\n请输入图书信息:\n");
printf("图书编号:"); /*输入图书编号(唯一)*/
scanf("%s", p0->book_num);
/*
"."与"->"的区别: "."是直接对结构体成员变量进行访问,
而"->"是通过指针(即结构体的地址)对结构体成员变量进行间接访问
*/
printf("图书名称:"); /*输入图书名称*/
scanf("%s", p0->book_name);
printf("图书作者:"); /*输入图书作者*/
scanf("%s", p0->book_writer);
printf("图书数量:"); /*输入图书数量*/
scanf("%d", &p0->book_kc);
p0->book_xy = p0->book_kc; /*开始时图书现有量和库存量相等*/
p0->next = NULL;
p0->n = ++n;
printf("\n图书信息初始化完毕!按任意键继续下一步操作..\n");
_getch();
/*
函数原型:int getch(void) 参数void
返回值:读取的字符的ASCII码值(整数)
读取方式:
直接用getch();会等待你按下任意键,再继续执行下面的语句;
用ch=getch();会等待你按下任意键之后,把该字符所对应的ASCII码赋给ch,再执行下面的语句。
*/
system("cls");
/*
system("cls")清屏
*/
}
/// <summary>
///
/// </summary>
void Insert_New_Book()/*新书入库*/
{
BK* p, * p0, * p1;
p = p1 = h_book;
printf("\n新书入库模块...\n");
printf("\n请输入新书信息..\n包括书号.书名.数量..\n");
p0 = (BK*)malloc(sizeof(BK));
printf("图书编号:");
scanf("%s", p0->book_num);
while (strcmp(p0->book_num, p1->book_num) != 0 && p1->next != NULL)
p1 = p1->next;
if (strcmp(p0->book_num, p1->book_num) == 0) /*此处分两种情况,若图书编号存在,则直接进库,只须输入书的数量*/
{
printf("\n此编号图书已存在!!直接入库!\n");
printf("图书数量:");
scanf("%d", &p0->book_kc);
p1->book_kc += p0->book_kc;
p1->book_xy += p0->book_kc;
}
else/*若不存在,则需要输入其他的信息,然后在进行插入操作*/
{
printf("图书名称:");
scanf("%s", p0->book_name);
printf("图书作者:");
scanf("%s", p0->book_writer);
printf("图书数量:");
scanf("%d", &p0->book_kc);//库存数量
while (p->next)
p = p->next;
if (h_book == NULL)
h_book = p0; /*此处分两种情况,链表中没有数据,head直接指向p0处*/
else
p->next = p0; /*此处分两种情况,链表中有数据,链表中最后元素的next指向p0处*/
p0->next = NULL;
p0->book_xy = p0->book_kc;
p0->n = ++n; ///链表长度增加
}
printf("\n新书入库完毕!按任意键继续下一步操作..\n");
_getch();
system("cls");
}
/// <summary>
/// 添加读者
/// </summary>
void add_reader()/*添加读者*/
{
RD* p0;
int i;
printf("\n读者初始化开始,请输入读者信息..\n包括书证号.姓名..\n");
p0 = (RD*)malloc(sizeof(RD)); /*申请新结点存储空间*/
h_reader = p0;
printf("\n请输入读者的信息:\n");
printf("读者书证号:");
scanf("%s", p0->reader_num);
printf("读者姓名:");
scanf("%s", p0->reader_name);
p0->right = 0;
for (i = 0; i < Max; i++)
{
strcpy(p0->borrow[i].borrow_book_num, "0"); /*所借图书直接置为(即没有借书)*/
strcpy(p0->borrow[i].limit_date, "0");
}
p0->next = NULL;
p0->m = ++m;
printf("\n读者信息初始化完毕!按任意键继续下一步操作..\n");
_getch();
system("cls");
}
void Borrow_Book() /*借书模块*/
{
BK* p0; RD* p1;
char bo_num[10], rea_num[10], lim_date[8];
int i;
p0 = h_book; p1 = h_reader;
printf("\n借书模块...\n");
printf("\n请输入借书的读者书证号:");
scanf("%s", rea_num);
while (p1->next != NULL && strcmp(rea_num, p1->reader_num) != 0)
p1 = p1->next;
if (p1->next == NULL && strcmp(rea_num, p1->reader_num) != 0)
{
printf("\n此读者编号不存在!按任意键返回..\n");
goto END;
}
printf("\n请输入你要借的书的编号:");
scanf("%s", bo_num);
while (strcmp(bo_num, p0->book_num) != 0 && p0->next != NULL)
p0 = p0->next;
if (p0->next == NULL && strcmp(bo_num, p0->book_num) != 0)
{
printf("\n此图书编号不存在!按任意键返回..\n");
goto END;
}
else if (p0->book_xy <= 0)
{
printf("\n抱歉,此书已借完!请等待新书的到来!!\n按任意键返回....");
goto END;
}
else if (p1->right > Max || p1->right == Max)
{
printf("\n不好意思,借书数目已满!不能借书!\n按任意键返回....");
goto END;
}
else if (strcmp(p1->borrow[0].borrow_book_num, "0") != 0)
{
for (i = 0; i < Max; i++)
{
if (strcmp(p1->borrow[i].borrow_book_num, bo_num) == 0)
{
printf("\n抱歉!同一个读者不能同借两本相同的书!\n按任意键返回....");
goto END;
}
else if (strcmp(p1->borrow[i].borrow_book_num, "0") == 0)
{
printf("\n请输入你要归还图书的日期:");
scanf("%s", lim_date);
strcpy(p1->borrow[p1->right++].borrow_book_num, bo_num);
strcpy(p1->borrow[p1->right - 1].limit_date, lim_date);
p0->book_xy--;
printf("\n读者编号%s借书完毕!按任意键继续下步操作..", p1->reader_num);
goto END;
}
}
}
else
{
printf("\n请输入你要归还图书的日期:");
scanf("%s", lim_date);
strcpy(p1->borrow[p1->right++].borrow_book_num, bo_num);
strcpy(p1->borrow[p1->right - 1].limit_date, lim_date);
p0->book_xy--;
p0->book_kc--;
printf("\n读者编号%s借书完毕!按任意键继续下步操作..", p1->reader_num);
goto END;
}
END:_getch(); system("cls");
}
void Return_Book() /*还书模块*/
{
BK* p; RD* q;
int i, j, find = 0;
char return_book_num[10], return_reader_num[10];
p = h_book; q = h_reader;
printf("\n还书模块...\n");
printf("\n请输入要还书的读者编号:");
scanf("%s", return_reader_num);
while (q->next != NULL && strcmp(return_reader_num, q->reader_num) != 0)
q = q->next;
if (q->next == NULL && strcmp(return_reader_num, q->reader_num) != 0)
{
find = 2;
printf("\n此读者编号不存在!按任意键返回..\n");
goto end;
}
printf("\n请输入读者还书的编号:");
scanf("%s", return_book_num);
while (p->next != NULL && strcmp(return_book_num, p->book_num) != 0)
p = p->next;
if (p->next == NULL && strcmp(return_book_num, p->book_num) != 0)
{
find = 2;
printf("\n错误!此图书编号不存在!按任意键返回..\n");
goto end;
}
for (i = 0; i < Max; i++)
if (strcmp(return_book_num, q->borrow[i].borrow_book_num) == 0) /*如果此读者借了此书*/
{
find = 1;
for (j = i; j < Max - 1; j++)
{
strcpy(q->borrow[j].borrow_book_num, q->borrow[j + 1].borrow_book_num);
strcpy(q->borrow[j].limit_date, q->borrow[j + 1].limit_date);
}
strcpy(q->borrow[Max - 1].borrow_book_num, "0");
strcpy(q->borrow[Max - 1].limit_date, "0");
p->book_xy++;
q->right--;
printf("\n编号%s的读者还书完毕!按任意键继续下步操作..", return_reader_num);
goto end;
}
if (find == 0)
printf("\n错误!此读者未借此书!按任意键返回..\n");
end: _getch(); system("cls");
}
/// <summary>
//
/// </summary>
//先获取链表的长度
void Print_book() /*查询图书信息*/
{
BK* p;
int i;
char e[10];
p = h_book;
printf("输入查询的图书编号:");
scanf("%s", e);
for (i = 0; i < n; i++)
{
if (strcmp(p->book_num, e) == 0)
{
printf("\n图书信息如下:\n\n");
printf("图书编号\t图书名称\t图书作者\t现有\t库存\n");
printf("%s\t\t%s\t\t%s\t\t%d\t%d\n", p->book_num, p->book_name, p->book_writer, p->book_xy, p->book_kc);
break;
}
else
p = p->next;
}
printf("\n图书信息打印完毕!按任意键继续下一步操作..");
_getch();
system("cls");
}
void Print_reader() /*查询读者信息*/
{
RD* p;
int i, j;
char e[10];
p = h_reader;
int m = 1;
printf("输入查询的读者编号:");
scanf("%s", e);
for (j = 0; j < m; j++)
{
m++;
if (strcmp(p->reader_num, e) == 0)
{
printf("\n读者信息如下:\n\n");
printf("读者书证号\t读者姓名\n");
printf("%s\t\t%s", p->reader_num, p->reader_name);
for (i = 0; i < Max; i++)
{
printf("\n");
printf("图书编号", i + 1);
printf("\t还书日期", i + 1);
printf("\n");
printf("\t%s", p->borrow[i].borrow_book_num);
printf("\t\t%s", p->borrow[i].limit_date);
}
printf("\n");
break;
}
else
p = p->next;
}
printf("\n读者信息打印完毕!按任意键继续下一步操作..");
_getch();
system("cls");
}
void Save() /*保存信息*/
{
Save_Reader();
Save_Book();
}
void Save_Reader() /*保存读者信息*/
{
FILE* fp_reader;
RD* p, * p0;
p = h_reader;
if ((fp_reader = fopen("Reader.txt", "wb")) == NULL) /*创建文件,进行保存*/
{
printf("\n文件保存失败!\n请重新启动本系统...\n");
exit(0);
}
while (p != NULL)
{
if (fwrite(p, sizeof(RD), 1, fp_reader) != 1) /*将链表中的信息写入文件中*/
printf("\n写入文件失败!\n请重新启动本系统!\n");
p0 = p;
p = p->next;
free(p0); /*释放所有结点*/
}
h_reader = NULL;
fclose(fp_reader); /*关闭文件*/
}
void Save_Book() /*保存图书信息*/
{
FILE* fp_book; /*创建文件型指针*/
BK* p, * p0;
p = h_book;
if ((fp_book = fopen("Book.txt", "wb")) == NULL) /*创建文件,进行保存*/
{
printf("\n文件保存失败!\n请重新启动本系统...\n");
exit(0);
}
while (p != NULL)
{
if (fwrite(p, sizeof(BK), 1, fp_book) != 1) /*将链表中的信息写入文件中*/
printf("\n写入文件失败!\n请重新启动本系统!\n");
p0 = p;
p = p->next;
free(p0);
}
h_book = NULL;
fclose(fp_book); /*关闭文件*/
}
void Load() /*加载信息*/
{
Load_Reader();
Load_Book();
}
void Load_Reader() /*加载读者信息*/
{
RD* p1, * p2, * p3;
FILE* fp; /*创建文件型指针*/
fp = fopen("Reader.txt", "rb"); /*打开文件*/
p1 = (RD*)malloc(sizeof(RD));
fread(p1, sizeof(RD), 1, fp);
/*
size_t fread( void *buffer, size_t size, size_t count,FILE *stream );
从一个文件流中读数据,读取count个元素,每个元素size字节.
如果调用成功返回count.如果调用成功则实际读取size*count字节
buffer的大小至少是 size*count 字节.
*/
h_reader = p3 = p2 = p1;
while (!feof(fp)) /*读出信息,重新链入链表*/
{
p1 = (RD*)malloc(sizeof(RD));
fread(p1, sizeof(RD), 1, fp);
p2->next = p1;
p3 = p2;
p2 = p1;
}
p3->next = NULL;
free(p1);
fclose(fp); /*关闭文件*/
}
void Load_Book() /*加载图书信息*/
{
BK* p1, * p2, * p3;
FILE* fp; /*创建文件型指针*/
fp = fopen("Book.txt", "rb"); /*打开文件*/
p1 = (BK*)malloc(sizeof(BK));
fread(p1, sizeof(BK), 1, fp);
h_book = p3 = p2 = p1;
while (!feof(fp)) /*读出信息,重新链入链表*/
{
p1 = (BK*)malloc(sizeof(BK));
fread(p1, sizeof(BK), 1, fp);
p2->next = p1;
p3 = p2;
p2 = p1;
}
p3->next = NULL;
free(p1);
fclose(fp); /*关闭文件*/
}
int main()
{
FILE* fp_book, * fp_reader; /*创建文件型指针*/
Login();
if ((fp_book = fopen("Book.txt", "rb")) == NULL || (fp_reader = fopen("Reader.txt", "rb")) == NULL) // 有b: fwrite写入时, 原原本本的写入数据.没b: fwrite写入时, \n会转成\r\n写入数据.
Init();
else
Load();
Menu_select(); /*调用主菜单*/
}
n
的维护。代码中全局变量n
被初始化为0,但在后续的操作中,没有看到对n
的更新。所以就导致在Print_book
函数中,for
循环的条件i < n
始终不满足,因为n
一直是0。所以循环体中的代码没有被执行,也就无法打印出图书的信息。n
进行相应的更新。比如,当新添加一本书时,n
应该增加1;当删除一本书时,n
应该减少1。book
结构体中也有一个n
字段。这可能会导致一些混淆,因为它与全局变量n
同名。建议将其改名以避免混淆。对Insert_New_Book
函数的修改,以展示如何更新n
:
void Insert_New_Book()/*新书入库*/
{
BK* p, * p0, * p1;
p = p1 = h_book;
printf("\n新书入库模块...\n");
printf("\n请输入新书信息..\n包括书号.书名.数量..\n");
p0 = (BK*)malloc(sizeof(BK));
printf("图书编号:");
scanf("%s", p0->book_num);
while (strcmp(p0->book_num, p1->book_num) != 0 && p1->next != NULL)
p1 = p1->next;
if (strcmp(p0->book_num, p1->book_num) == 0)
{
// ...原来的代码...
}
else
{
// ...原来的代码...
// 新添加的代码,用于更新 n
n++;
}
}
按照这种方式,对所有添加或删除图书信息的函数进行相应的修改,以保证n
的值始终能正确反映链表的长度。
在堆区开辟内存存储数据时,new关键字的使用方式错误,将“[]”写为了“()”
在笔者将自己的代码与视频教程中的代码对比后,笔者发现了原因。
在有参构造函数、拷贝构造函数,以及重载赋值运算符函数这三个函数中,需要在堆区上开辟一段连续的内存,用来存储数组的元素。
要做到这一点,就需要使用new关键字
具体语法为:
接收指针p = new 数据类型 [元素个数]
其中,用来包含元素个数的是中括号“[]”
但笔者在代码中却使用了小括号“()”
以有参构造函数为例:
错误的写法:
template<typename T>
MyArray<T>::MyArray(int capacity)
{
this->m_arr = new T(capacity);//错误的写法
this->m_size = 0;
this->m_capacity = capacity;
}
正确的写法:
template<typename T>
MyArray<T>::MyArray(int capacity)
{
this->m_arr = new T[capacity];//正确的写法
this->m_size = 0;
this->m_capacity = capacity;
}
new T[capacity]
的含义是,在堆区开辟大小为capacity个T类型数据的内存,并返回第一个数据的指针。
而new T(capacity)
的含义则是,在堆区开辟大小为一个T类型数据的内存,将这个T类型数据的值初始化为capacity。
正是因为笔者写成了后者,所以才导致在测试时,以为创建了5个元素大小的数组,实际上只创建了一个值为5的元素。
而此时size又是5,自然会导致指针访问越界,从而触发断点。
int main()
{
MyArray<int> arr(5);
int capacity = arr.GetCapacity();
for (int i = 0; i < capacity; i++)
{
arr.PushBack(i);
}
int size = arr.GetSize();
for (int i = 0; i < size; i++)
{
cout << arr[i]<<endl;
}
}
c++实现图书管理系统
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
//3.数据的设计
//3.1程序的数据存储--->容器
//3.2数据的结构 --->图书的信息
struct bookInfo
{
char name[20]; //书名
float price; //书籍的价格
int num; //书籍的数量
};
//定义链表
struct Node
{
struct bookInfo data;
struct Node* next;
};
struct Node* list = NULL; //将链表声明成全局变量
//创建表头:表头就是结构体变量
struct Node* createHead()
{
//动态内存申请
struct Node* headNode = (struct Node*)malloc(sizeof(struct Node));
//变量初始化
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;
}
//尾插法
/*struct insertNodeByTall(struct Node* headNode, int data)
{
struct Node* pMove = headNode;
while (pMove != NULL)
{
pMove = pMove->next;
}
struct Node* newNode = createHead(data);
pMove->next = newNode;
}*/
//指定删除(删除链表中元素)
//posLeftNode->next=posNode->next;
//free(posNode);
void deleteNodeByName(struct Node* headNode, char* bookname)
{
struct Node* posLeftNode = headNode;
struct Node* posNode = headNode->next;
//书籍名字是字符串,字符串比较函数
while (posNode != NULL && strcmp(posNode->data.name, bookname))
{
posLeftNode = posNode;
posNode = posLeftNode->next;
}
//讨论查找的结果
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))
{
posNode = posNode->next;
}
return posNode;
}
//打印链表
void printList(struct Node* headNode)
{
struct Node* pMove = headNode->next;
printf("书名\t价格\t数量\n");
while (pMove != NULL)
{
printf("%s\t%.1f\t%d\n", pMove->data.name, pMove->data.price, pMove->data.num);
pMove = pMove->next;
}
}
//直接文件操作
//文件写操作
void saveInfoToFile(const char* filename, struct Node* headNode)
{
FILE* fp = fopen(filename, "w");
struct Node* pMove = headNode->next;
while (pMove != NULL)
{
fprintf(fp, "%s\t%.1f\t%d\n", pMove->data.name, pMove->data.price, pMove->data.num);
pMove = pMove->next;
}
fclose(fp);
}
//文件读操作
void readInfoFromFile(const char* fileName, struct Node* headNode)
{
FILE* fp = fopen(fileName, "r");
if (fp == NULL)
{
//不存在就创建出来这个文件
fp = fopen(fileName, "w+");
}
struct bookInfo tempData;
while (fscanf(fp, "%s\t%f\t%d\n", tempData.name, &tempData.price, &tempData.num) != EOF)
{
insertNodeByHead(list, tempData);
}
fclose(fp);
}
//冒泡排序(链表)
void bubbleSortList(struct Node* headNode)
{
for (struct Node* p = headNode->next; p != NULL; p = p->next)
{
for (struct Node* q = headNode->next; q->next != NULL; q = q->next)
{
if (q->data.price > q->next->data.price)
{
//交换值
struct bookInfo tempData = q->data;
q->data = q->next->data;
q->next->data = tempData;
}
}
}
printList(headNode);
}
//2.交互
void keyDown()
{
int userkey = 0;
struct bookInfo tempBook; //产生一个临时的变量存储书籍信息
struct Node* result = NULL;
scanf("%d", &userkey);
switch (userkey) {
case 0:
printf(" 【 登记 】 \n");
printf("输入书籍的信息(name,price,num):");
scanf("%s%f%d", tempBook.name, &tempBook.price, &tempBook.num);
insertNodeByHead(list, tempBook);
saveInfoToFile("bookinfo.txt", list);
break;
case 1:
printf(" 【 浏览 】 \n");
printList(list);
break;
case 2:
printf(" 【 借阅 】 \n");
printf("请输入你要借阅的书籍:");
scanf("%s", tempBook.name);
result = searchByName(list,tempBook.name);
if (result == NULL)
printf("没有相关书籍无法借阅!\n");
else
{
if (result->data.num > 0)
{
result->data.num--;
printf("借阅成功\n");
saveInfoToFile("bookinfo.txt", list);
}
else
{
printf("当前书籍无库存,借阅失败!\n");
}
}
break;
case 3:
printf(" 【 归还 】 \n");
printf("请输入你要归还的书籍:");
scanf("%s", tempBook.name);
result = searchByName(list, tempBook.name);
if (result == NULL)
printf("书籍来源非法!\n");
else
{
result->data.num++;
printf("书籍归还成功!\n");
saveInfoToFile("bookinfo.txt", list);
}
break;
case 4:
printf(" 【 查找 】 \n");
printf("你要查询的书名:");
scanf("%s", tempBook.name);
result = searchByName(list, tempBook.name);
if (result == NULL)
{
printf("未找到相关结果!\n");
}
else
{
printf("书名\t价格\t数量\n");
printf("%s\t%.1f\t%d\n", result->data.name, result->data.price, result->data.num);
}
break;
case 5:
printf(" 【 排序 】 \n");
bubbleSortList(list);
break;
case 6:
printf(" 【 删除 】 \n");
printf("输入想要删除的书名:");
scanf("%s", tempBook.name);
deleteNodeByName(list, tempBook.name);
saveInfoToFile("bookinfo.txt", list);
break;
case 7:
printf(" 【 退出 】 \n");
printf(" 退出成功 \n");
system("pause");
exit(0); //关掉整个程序
break;
default:
printf(" 【 error 】 \n");
break;
}
}
//1.界面--->菜单--->模块
void makeMenu()
{
printf("----------------------------------\n");
printf(" 图书管理借阅系统\n");
printf("t0.登记书籍\n");
printf("t1.浏览书籍\n");
printf("t2.借阅书籍\n");
printf("t3.归还书籍\n");
printf("t4.查找书籍\n");
printf("t5.排序书籍\n");
printf("t6.删除书籍\n");
printf("t7.退出系统\n");
printf("----------------------------------\n");
printf("请输入(0~7):");
}
int main()
{
list = createHead(); //链表初始化
readInfoFromFile("bookinfo.txt", list);
while (1)
{
makeMenu();
keyDown();
system("pause");
system("cls");
}
}
我运行了代码,结果是正确的,能够查询出图书信息。你调试过吗,IDE用的是VS吧?
读文件的两个Load函数有问题,代码修改如下:
#define _CRT_SECURE_NO_WARNINGS 1
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include <string.h>
#include <stdlib.h>
#include<conio.h>
#define Max 4
typedef struct book
{
char book_num[10]; // 图书编号
char book_name[20]; // 图书名称
char book_writer[10]; // 图书作者
int book_xy; // 图书现有量
int book_kc; // 库存数量
int n; //链表长度
struct book* next;
}BK;
typedef struct borrow
{
char borrow_book_num[10];
char limit_date[10];
}BO;
typedef struct reader
{
char reader_num[10];
char reader_name[10];
int right;
int m; //链表长度
BO borrow[Max];
struct reader* next;
}RD;
BK* h_book=0;
RD* h_reader=0;
int n = 0;
int m = 0;
void Login();
int Menu();
void Init();
void Menu_select();
void Insert_New_Book();
void add_reader();
void Print_reader();
void Print_book();
void Borrow_Book();
void Return_Book();
void Save();
void Save_Book();
void Save_Reader();
void Load();
void Load_Reader();
void Load_Book();
void Login()
{
system("cls");
printf("\n\n\n\t\t***************************************\n");
printf("\n\n\n\t\t** 欢迎使用图书管理系统 **\n");
printf("\n\n\n\t\t***************************************\n");
printf("\n\n\n\t\t 按任意键进入系统...");
_getch();
system("cls");
}
int Menu() /*主菜单*/
{
int dm;
printf("\n\t\t图书管理系统主菜单\n");
printf("=================================================\n");
printf("*\t1----采编入库 \n");
printf("*\t2----登记读者 \n");
printf("*\t3----借阅登记 \n");
printf("*\t4----还书管理 \n");
printf("*\t5----查询图书信息 \n");
printf("*\t6----查询读者信息 \n");
printf("*\t0----退出系统 \n");
printf("=================================================\n");
printf("请选择相应的代码:");
for (;;)
{
scanf("%d", &dm); //dm输入的数字
if (dm < 0 || dm>7)
printf("\n错误!请重新输入:");
else
break;
}
return dm;
}
void Menu_select()/*主菜单选择函数*/
{
for (;;)
{
switch (Menu()) /*功能选择*/
{
case 0:
system("cls");
Save();
printf("\n\n\t文件保存成功!\n");
printf("\n\n\t欢迎下次使用本系统!\n");
_getch();
exit(0);
case 1: Insert_New_Book(); break;
case 2: add_reader(); break;
case 3: Borrow_Book(); break;
case 4: Return_Book(); break;
case 5: Print_book(); break;
case 6: Print_reader(); break;
default:printf("\n错误!");
exit(0);
}
}
}
/// <summary>
///
/// </summary>
void Init() /*初始化*/
{
BK* p0;
printf("\n图书初始化开始,请输入图书信息..\n包括编号.书名.数量..\n");
p0 = (BK*)malloc(sizeof(BK));
/*
malloc函数的原型为:void *malloc (unsigned int size)
其作用是在内存的动态存储区中分配一个长度为size的连续空间。
其参数是一个无符号整形数,
返回值是一个指向所分配的连续存储域的起始地址的指针。
*/
h_book = p0;
printf("\n请输入图书信息:\n");
printf("图书编号:"); /*输入图书编号(唯一)*/
scanf("%s", p0->book_num);
/*
"."与"->"的区别: "."是直接对结构体成员变量进行访问,
而"->"是通过指针(即结构体的地址)对结构体成员变量进行间接访问
*/
printf("图书名称:"); /*输入图书名称*/
scanf("%s", p0->book_name);
printf("图书作者:"); /*输入图书作者*/
scanf("%s", p0->book_writer);
printf("图书数量:"); /*输入图书数量*/
scanf("%d", &p0->book_kc);
p0->book_xy = p0->book_kc; /*开始时图书现有量和库存量相等*/
p0->next = NULL;
p0->n = ++n;
printf("\n图书信息初始化完毕!按任意键继续下一步操作..\n");
_getch();
/*
函数原型:int getch(void) 参数void
返回值:读取的字符的ASCII码值(整数)
读取方式:
直接用getch();会等待你按下任意键,再继续执行下面的语句;
用ch=getch();会等待你按下任意键之后,把该字符所对应的ASCII码赋给ch,再执行下面的语句。
*/
system("cls");
/*
system("cls")清屏
*/
}
/// <summary>
///
/// </summary>
void Insert_New_Book()/*新书入库*/
{
BK* p, * p0, * p1;
p = p1 = h_book;
printf("\n新书入库模块...\n");
printf("\n请输入新书信息..\n包括书号.书名.数量..\n");
p0 = (BK*)malloc(sizeof(BK));
printf("图书编号:");
scanf("%s", p0->book_num);
while (strcmp(p0->book_num, p1->book_num) != 0 && p1->next != NULL)
p1 = p1->next;
if (strcmp(p0->book_num, p1->book_num) == 0) /*此处分两种情况,若图书编号存在,则直接进库,只须输入书的数量*/
{
printf("\n此编号图书已存在!!直接入库!\n");
printf("图书数量:");
scanf("%d", &p0->book_kc);
p1->book_kc += p0->book_kc;
p1->book_xy += p0->book_kc;
}
else/*若不存在,则需要输入其他的信息,然后在进行插入操作*/
{
printf("图书名称:");
scanf("%s", p0->book_name);
printf("图书作者:");
scanf("%s", p0->book_writer);
printf("图书数量:");
scanf("%d", &p0->book_kc);//库存数量
while (p->next)
p = p->next;
if (h_book == NULL)
h_book = p0; /*此处分两种情况,链表中没有数据,head直接指向p0处*/
else
p->next = p0; /*此处分两种情况,链表中有数据,链表中最后元素的next指向p0处*/
p0->next = NULL;
p0->book_xy = p0->book_kc;
p0->n = ++n; ///链表长度增加
}
printf("\n新书入库完毕!按任意键继续下一步操作..\n");
_getch();
system("cls");
}
/// <summary>
/// 添加读者
/// </summary>
void add_reader()/*添加读者*/
{
RD* p0;
int i;
printf("\n读者初始化开始,请输入读者信息..\n包括书证号.姓名..\n");
p0 = (RD*)malloc(sizeof(RD)); /*申请新结点存储空间*/
h_reader = p0;
printf("\n请输入读者的信息:\n");
printf("读者书证号:");
scanf("%s", p0->reader_num);
printf("读者姓名:");
scanf("%s", p0->reader_name);
p0->right = 0;
for (i = 0; i < Max; i++)
{
strcpy(p0->borrow[i].borrow_book_num, "0"); /*所借图书直接置为(即没有借书)*/
strcpy(p0->borrow[i].limit_date, "0");
}
p0->next = NULL;
p0->m = ++m;
printf("\n读者信息初始化完毕!按任意键继续下一步操作..\n");
_getch();
system("cls");
}
void Borrow_Book() /*借书模块*/
{
BK* p0; RD* p1;
char bo_num[10], rea_num[10], lim_date[8];
int i;
p0 = h_book; p1 = h_reader;
printf("\n借书模块...\n");
printf("\n请输入借书的读者书证号:");
scanf("%s", rea_num);
while (p1->next != NULL && strcmp(rea_num, p1->reader_num) != 0)
p1 = p1->next;
if (p1->next == NULL && strcmp(rea_num, p1->reader_num) != 0)
{
printf("\n此读者编号不存在!按任意键返回..\n");
goto END;
}
printf("\n请输入你要借的书的编号:");
scanf("%s", bo_num);
while (strcmp(bo_num, p0->book_num) != 0 && p0->next != NULL)
p0 = p0->next;
if (p0->next == NULL && strcmp(bo_num, p0->book_num) != 0)
{
printf("\n此图书编号不存在!按任意键返回..\n");
goto END;
}
else if (p0->book_xy <= 0)
{
printf("\n抱歉,此书已借完!请等待新书的到来!!\n按任意键返回....");
goto END;
}
else if (p1->right > Max || p1->right == Max)
{
printf("\n不好意思,借书数目已满!不能借书!\n按任意键返回....");
goto END;
}
else if (strcmp(p1->borrow[0].borrow_book_num, "0") != 0)
{
for (i = 0; i < Max; i++)
{
if (strcmp(p1->borrow[i].borrow_book_num, bo_num) == 0)
{
printf("\n抱歉!同一个读者不能同借两本相同的书!\n按任意键返回....");
goto END;
}
else if (strcmp(p1->borrow[i].borrow_book_num, "0") == 0)
{
printf("\n请输入你要归还图书的日期:");
scanf("%s", lim_date);
strcpy(p1->borrow[p1->right++].borrow_book_num, bo_num);
strcpy(p1->borrow[p1->right - 1].limit_date, lim_date);
p0->book_xy--;
printf("\n读者编号%s借书完毕!按任意键继续下步操作..", p1->reader_num);
goto END;
}
}
}
else
{
printf("\n请输入你要归还图书的日期:");
scanf("%s", lim_date);
strcpy(p1->borrow[p1->right++].borrow_book_num, bo_num);
strcpy(p1->borrow[p1->right - 1].limit_date, lim_date);
p0->book_xy--;
p0->book_kc--;
printf("\n读者编号%s借书完毕!按任意键继续下步操作..", p1->reader_num);
goto END;
}
END:_getch(); system("cls");
}
void Return_Book() /*还书模块*/
{
BK* p; RD* q;
int i, j, find = 0;
char return_book_num[10], return_reader_num[10];
p = h_book; q = h_reader;
printf("\n还书模块...\n");
printf("\n请输入要还书的读者编号:");
scanf("%s", return_reader_num);
while (q->next != NULL && strcmp(return_reader_num, q->reader_num) != 0)
q = q->next;
if (q->next == NULL && strcmp(return_reader_num, q->reader_num) != 0)
{
find = 2;
printf("\n此读者编号不存在!按任意键返回..\n");
goto end;
}
printf("\n请输入读者还书的编号:");
scanf("%s", return_book_num);
while (p->next != NULL && strcmp(return_book_num, p->book_num) != 0)
p = p->next;
if (p->next == NULL && strcmp(return_book_num, p->book_num) != 0)
{
find = 2;
printf("\n错误!此图书编号不存在!按任意键返回..\n");
goto end;
}
for (i = 0; i < Max; i++)
if (strcmp(return_book_num, q->borrow[i].borrow_book_num) == 0) /*如果此读者借了此书*/
{
find = 1;
for (j = i; j < Max - 1; j++)
{
strcpy(q->borrow[j].borrow_book_num, q->borrow[j + 1].borrow_book_num);
strcpy(q->borrow[j].limit_date, q->borrow[j + 1].limit_date);
}
strcpy(q->borrow[Max - 1].borrow_book_num, "0");
strcpy(q->borrow[Max - 1].limit_date, "0");
p->book_xy++;
q->right--;
printf("\n编号%s的读者还书完毕!按任意键继续下步操作..", return_reader_num);
goto end;
}
if (find == 0)
printf("\n错误!此读者未借此书!按任意键返回..\n");
end: _getch(); system("cls");
}
/// <summary>
//
/// </summary>
//先获取链表的长度
void Print_book() /*查询图书信息*/
{
BK* p;
int i;
char e[10];
p = h_book;
printf("输入查询的图书编号:");
scanf("%s", e);
for (i = 0; i < n; i++)
{
if (strcmp(p->book_num, e) == 0)
{
printf("\n图书信息如下:\n\n");
printf("图书编号\t图书名称\t图书作者\t现有\t库存\n");
printf("%s\t\t%s\t\t%s\t\t%d\t%d\n", p->book_num, p->book_name, p->book_writer, p->book_xy, p->book_kc);
break;
}
else
p = p->next;
}
printf("\n图书信息打印完毕!按任意键继续下一步操作..");
_getch();
system("cls");
}
void Print_reader() /*查询读者信息*/
{
RD* p;
int i, j;
char e[10];
p = h_reader;
int m = 1;
printf("输入查询的读者编号:");
scanf("%s", e);
for (j = 0; j < m; j++)
{
m++;
if (strcmp(p->reader_num, e) == 0)
{
printf("\n读者信息如下:\n\n");
printf("读者书证号\t读者姓名\n");
printf("%s\t\t%s", p->reader_num, p->reader_name);
for (i = 0; i < Max; i++)
{
printf("\n");
printf("图书编号", i + 1);
printf("\t还书日期", i + 1);
printf("\n");
printf("\t%s", p->borrow[i].borrow_book_num);
printf("\t\t%s", p->borrow[i].limit_date);
}
printf("\n");
break;
}
else
p = p->next;
}
printf("\n读者信息打印完毕!按任意键继续下一步操作..");
_getch();
system("cls");
}
void Save() /*保存信息*/
{
Save_Reader();
Save_Book();
}
void Save_Reader() /*保存读者信息*/
{
FILE* fp_reader;
RD* p, * p0;
p = h_reader;
if ((fp_reader = fopen("Reader.txt", "wb")) == NULL) /*创建文件,进行保存*/
{
printf("\n文件保存失败!\n请重新启动本系统...\n");
exit(0);
}
while (p != NULL)
{
if (fwrite(p, sizeof(RD), 1, fp_reader) != 1) /*将链表中的信息写入文件中*/
printf("\n写入文件失败!\n请重新启动本系统!\n");
p0 = p;
p = p->next;
free(p0); /*释放所有结点*/
}
h_reader = NULL;
fclose(fp_reader); /*关闭文件*/
}
void Save_Book() /*保存图书信息*/
{
FILE* fp_book; /*创建文件型指针*/
BK* p, * p0;
p = h_book;
if ((fp_book = fopen("Book.txt", "wb")) == NULL) /*创建文件,进行保存*/
{
printf("\n文件保存失败!\n请重新启动本系统...\n");
exit(0);
}
while (p != NULL)
{
if (fwrite(p, sizeof(BK), 1, fp_book) != 1) /*将链表中的信息写入文件中*/
printf("\n写入文件失败!\n请重新启动本系统!\n");
p0 = p;
p = p->next;
free(p0);
}
h_book = NULL;
fclose(fp_book); /*关闭文件*/
}
void Load() /*加载信息*/
{
Load_Reader();
Load_Book();
}
void Load_Reader() /*加载读者信息*/
{
RD* p1, * p2 = 0;// , * p3;
FILE* fp; /*创建文件型指针*/
fp = fopen("Reader.txt", "rb"); /*打开文件*/
//p1 = (RD*)malloc(sizeof(RD));
//fread(p1, sizeof(RD), 1, fp);
/*
size_t fread( void *buffer, size_t size, size_t count,FILE *stream );
从一个文件流中读数据,读取count个元素,每个元素size字节.
如果调用成功返回count.如果调用成功则实际读取size*count字节
buffer的大小至少是 size*count 字节.
*/
//h_reader = p3 = p2 = p1;
while (!feof(fp)) /*读出信息,重新链入链表*/
{
p1 = (RD*)malloc(sizeof(RD));
p1->next = 0;
if (fread(p1, sizeof(RD), 1, fp) == 1)
{
if (h_reader == 0)
{
h_reader = p1;
p2 = p1;
}
else
{
p2->next = p1;
p2 = p1;
}
m++;
}
else
free(p1);
//p2->next = p1;
//p3 = p2;
//p2 = p1;
}
if(h_reader)
h_reader->m = m;
//p2->next = NULL;
//free(p1);
fclose(fp); /*关闭文件*/
}
void Load_Book() /*加载图书信息*/
{
BK* p1, * p2 = 0;// , * p3;
FILE* fp; /*创建文件型指针*/
fp = fopen("Book.txt", "rb"); /*打开文件*/
//p1 = (BK*)malloc(sizeof(BK));
//fread(p1, sizeof(BK), 1, fp);
//n++;
//h_book = p2 = p1;
while (!feof(fp)) /*读出信息,重新链入链表*/
{
p1 = (BK*)malloc(sizeof(BK));
p1->next = 0;
if (fread(p1, sizeof(BK), 1, fp) == 1)
{
if (h_book == 0)
{
h_book = p1;
p2 = p1;
}
else
{
p2->next = p1;
p2 = p1;
}
n++;
}
else
free(p1);
//p2->next = p1;
//p3 = p2;
//p2 = p1;
//n++;
}
//p2->next = NULL;//p3->next = NULL;
//free(p1);
fclose(fp); /*关闭文件*/
if(h_book)
h_book->n = n;
}
int main()
{
FILE* fp_book, * fp_reader; /*创建文件型指针*/
Login();
if ((fp_book = fopen("Book.txt", "rb")) == NULL || (fp_reader = fopen("Reader.txt", "rb")) == NULL) // 有b: fwrite写入时, 原原本本的写入数据.没b: fwrite写入时, \n会转成\r\n写入数据.
Init();
else
Load();
Menu_select(); /*调用主菜单*/
}
没有对链表的头节点进行初始化。因此,如果链表为空,则n的值将始终为0,导致for循环不会执行。
要解决这个问题,你需要在程序的某个地方初始化链表头。
int main()
{
h_book = NULL; // 初始化链表头
...
}
另外,如果链表为空,你应该添加一个条件语句来处理这种情况。例如,在Print_book函数中,你可以添加以下代码:
void Print_book() /*查询图书信息*/
{
BK* p;
int i;
char e[10];
p = h_book;
printf("输入查询的图书编号:");
scanf("%s", e);
if (h_book == NULL) { // 链表为空
printf("图书信息为空。\n");
printf("\n图书信息打印完毕!按任意键继续下一步操作..");
_getch();
system("cls");
return;
}
for (i = 0; i < n; i++)
{
if (strcmp(p->book_num, e) == 0)
{
printf("\n图书信息如下:\n\n");
printf("图书编号\t图书名称\t图书作者\t现有\t库存\n");
printf("%s\t\t%s\t\t%s\t\t%d\t%d\n", p->book_num, p->book_name, p->book_writer, p->book_xy, p->book_kc);
break;
}
else
p = p->next;
}
printf("\n图书信息打印完毕!按任意键继续下一步操作..");
_getch();
system("cls");
}
你需要初始化链表,或者将变量n声明为全局变量,直接初始化都可以
首先 int n = 0; 初始化链表长度为0
然后 更新链表长度 n++;
你在查询方法Print_book中,没有初始化链表长度n啊,在代码中,没有看到你的n被初始化。如果n是全局的,那么你应该写成静态全局的变量,并且在添加书籍的方法中,每添加本书籍信息,n+1 使得n的值始终为当前书籍信息的总大小。
将变量n声明为全局变量
在您提供的代码中,变量n
在Print_book()
函数中始终为0,导致不执行for
循环。这是因为在Init()
函数中对n
进行了自增操作,但是在其他函数中并没有更新n
的值。
为了解决这个问题,您可以将变量n
声明为全局变量,并在需要更新它的地方进行适当的修改。具体来说,在Insert_New_Book()
函数中,当插入新的图书时,您需要更新n
的值。修改后的代码如下所示:
void Insert_New_Book()
{
BK* p0;
printf("\n请输入图书信息:\n");
p0 = (BK*)malloc(sizeof(BK));
h_book->n++; // 更新链表长度
// 输入图书信息...
p0->n = h_book->n;
p0->next = NULL;
printf("\n图书信息录入完毕!按任意键继续下一步操作..");
_getch();
system("cls");
}
此外,您还需要在其他涉及到链表长度的地方进行相应的更新,以确保链表长度正确地反映了链表中的节点数量。
希望这可以帮助您解决问题!