C语言单链表实现图书管理系统源码解析
本教程通过C语言中的单链表和结构体,构建一个具备增删改查功能的图书管理系统。核心在于利用链表动态管理书籍信息,并通过文件读写(fopen/fprintf/fscanf)实现数据的本地保存,确保程序重启后记录不丢失。
系统架构与基础设计
图书管理系统需要处理多个书籍对象,每个对象包含书名、价格和库存数量。采用单链表作为底层数据结构,相比静态数组,它可以动态分配内存,便于在运行时灵活增加或移除书籍节点。
第1步:定义数据结构
目的:明确数据存储格式和链表节点形态。
struct book:容器结构体,包含name(书名)、price(价格)和num(数量)。struct Node:链表节点,包含上述数据域data和指向下一个节点的指针next。
struct book {
char name[20];
float price;
int num; //书的数量
};
//3 数据容器——链表
struct Node {
struct book data;
struct Node* next;
};
struct Node* headnode = NULL; //全局头指针第2步:初始化与节点操作
目的:建立空链表并支持插入新节点。
创建表头:使用malloc动态申请空间,将next置为NULL,返回头结点指针。
struct Node* createlisthead() {
struct Node* headnode = (struct Node*)malloc(sizeof(struct Node));
if(headnode == NULL) return NULL;
headnode->next = NULL;
return headnode;
}头插法新增节点:先创建新节点存放数据,调整指针方向(先连新节点后继,再连头节点),完成插入。
void insertbyhead(struct Node* headnode, struct book data) {
struct Node* newnode = createnewnode(data);
//必须先连后断,防止链表断裂
newnode->next = headnode->next;
headnode->next = newnode;
}
struct Node* createnewnode(struct book data) {
struct Node* newnode = (struct Node*)malloc(sizeof(struct Node));
newnode->data = data;
newnode->next = NULL;
return newnode;
}核心功能实现
第3步:遍历与打印链表
目的:展示当前所有书籍信息。
从表头的next开始遍历,直到指针为NULL。注意格式化输出以对齐显示。
void printflist(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;
}
printf("\n");
}第4步:查找与删除节点
目的:根据书名定位并移除特定书籍。
查找逻辑:遍历链表,若找到名称匹配节点则返回指针,否则返回NULL。
删除逻辑:需保留前驱节点(posleftnode)以便修改其next指针指向目标的后继节点,最后释放目标节点内存并置空,防止悬空指针。
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 = posnode->next;
}
if (posnode == NULL) {
printf("未找到数据\n");
return;
} else {
posleftnode->next = posnode->next; //断开链接
free(posnode);
posnode = NULL;
printflist(headnode); //删除后刷新界面
}
}');第5步:冒泡排序(按价格)
目的:对书籍列表进行降序或升序排列。
采用交换数据域的方式而非交换节点位置,因为本题结构中数据较小,交换内容效率更高且逻辑更简单。外层循环控制趟数,内层循环比较相邻元素。
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 book tempdata = q->data;
q->data = q->next->data;
q->next->data = tempdata;
}
}
}
printflist(headnode);
}数据持久化(文件存储)
若不保存数据,每次关闭控制台程序输入的信息将丢失。通过文件操作可以实现数据持久化。
第6步:文件写入操作
目的:将链表中的数据保存到book.txt文件中。
打开文件模式为"w"(覆盖写),遍历链表并使用fprintf逐个写入字段,保持制表符分隔以便后续读取。
void savefile(const char* filename, struct Node* headnode) {
FILE* fp = fopen(filename, "w");
if (fp == NULL) return; // 容错检查
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);
fp = NULL;
}第7步:文件读取操作
目的:启动时加载已有数据到链表。
尝试以"r"模式打开文件。如果文件不存在(返回NULL),则新建一个空文件"w+"。随后循环调用fscanf读取三元组,通过insertbyhead依次加入链表。注意读取时需用指针传递浮点数地址。
void readfile(const char *filename, struct Node* headnode) {
FILE* fp = fopen(filename, "r");
if (fp == NULL) {
fp = fopen(filename, "w+"); // 无文件则创建
}
struct book tempdata;
// fscanf 返回值等于字段数表示成功
while (fscanf(fp, "%s\t%f\t%d\n", tempdata.name,
&tempdata.price, &tempdata.num) != EOF) {
insertbyhead(headnode, tempdata);
}
fclose(fp);
fp = NULL;
}交互逻辑整合
main函数流程:初始化链表头 -> 读取文件数据进入链表 -> 进入死循环等待菜单指令 -> 执行对应操作 -> 清屏。
借阅与归还逻辑细节
借阅时需判断是否存在该书籍且库存num > 0,成功后数量减1;归还需判断来源合法性(即书中是否真有此书),成功后数量加1。这两个操作不需要保存文件,仅在下次保存或退出时才落盘。
完整菜单控制代码
void menu() {
printf("---------------------------------\n");
printf("\t图书管理系统\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\n");
}
int main() {
headnode = createlisthead();
readfile("book.txt", headnode); // 加载历史数据
int input = 0;
while (1) {
system("cls"); // Windows下清屏
menu();
scanf("%d", &input);
switch (input) {
case 0:
savefile("book.txt", headnode); // 退出前务必保存
printf("【退出】\n退出成功\n");
exit(0);
case 1: { // 登记
struct book tempbook;
printf("输入书籍的信息(name,price,num): ");
scanf("%s%f%d", tempbook.name, &tempbook.price, &tempbook.num);
insertbyhead(headnode, tempbook);
break;
}
case 2: printflist(headnode); break; // 浏览
case 3: { // 借阅
char name[20];
printf("请输入要借阅的书名: ");
scanf("%s", name);
struct Node* res = searchbyname(headnode, name);
if (!res || res->data.num <= 0) printf("无法借阅(无书或无库存)\n");
else {
res->data.num--;
printf("借阅成功\n");
}
break;
}
case 4: { // 归还
char name[20];
printf("请输入要归还的书名: ");
scanf("%s", name);
struct Node* res = searchbyname(headnode, name);
if (!res) printf("系统中无此书记录,来源非法\n");
else {
res->data.num++;
printf("书籍归还成功!\n");
}
break;
}
case 5: bubblesortlist(headnode); break; // 排序
case 6: { // 删除
char name[20];
printf("输入要删除的书名: ");
scanf("%s", name);
deletenodebyname(headnode, name);
break;
}
case 7: { // 查找
char name[20];
printf("请输入要查找的书籍: ");
scanf("%s", name);
struct Node* res = searchbyname(headnode, name);
if (!res) printf("未找到相关信息!\n");
else {
printf("书名\t价格\t数量\n");
printf("%s\t%.1f\t%d\n", res->data.name, res->data.price, res->data.num);
}
break;
}
default: printf("选择错误\n");
}
system("pause");
}
return 0;
}以上就是利用C语言单链表开发图书管理系统的详细内容,更多关于C语言链表编程的资料请关注本站其它相关文章!
免责声明:本文内容仅供参考,不代表本站观点。转载或引用请注明出处。









