300行代码速通C语言指针链表、学会文件读取。多刷!!大佬的视频讲解请见参考部分。学会这个大一拿下!
系统功能包含:添加、删除、排序、查询、文件读取等。
编译器:devc++
如果遇到for循环中不能定义,即for(int i=0; i<6; i++);
请参考:Dev C++ C语言中for循环中声明循环控制变量的问题_devc++ for中设置变量-CSDN博客
0、头文件
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
1、菜单
简单页面设计,可自己设计。
//1.make Menu-模块
void makeMenu() {
printf("+---------------------------------+\n");
printf("| Books Management System |\n");
printf("+---------------------------------+\n");
printf("0 退出系统\n");
printf("1 登记书籍\n"); //添加
printf("2 浏览书籍\n"); //显示
printf("3 借阅书籍\n"); //修改
printf("4 归还书籍\n");
printf("5 书籍排序\n");
printf("6 删除书籍\n"); //删除
printf("7 查找书籍\n\n"); //查询
printf("请选择(0~7):");
}
2、交互功能
使用switch实现选择菜单功能的效果(主框架),在后续其它功能的完善中会补充完全。
//2.做交互-按键处理-跳转
void keyDown() {
int userKey = 0;
scanf("%d",&userKey);
switch(userKey) {
case 0:
printf("[退出成功]\n");
break;
case 1:
printf("[登记]\n");
break;
case 2:
printf("[浏览]\n");
break;
case 3:
printf("[借阅]\n"); //书籍存在可借阅,数量-1;不存在,节约失败
break;
case 4:
printf("[归还]\n"); //书籍数量+1
break;
case 5:
printf("[排序]\n");
BubbleSortList(list);
break;
case 6:
printf("[删除]\n");
break;
case 7:
printf("[查找]\n");
break;
default:
printf("[Error! 请输入0~7之间的数字!]\n");
break;
}
}
3、系统设计
3.1 选择容器->链表
包含了浏览、添加、删除功能的函数编写。
//3.1 链表 =结构体变量
//3.1.1创建链表:
struct Node {
struct bookInfo data;
struct Node *next;
};
//3.1.2创建表头;表头就是结构体变量
struct Node* createHead() {
//内存动态申请
struct Node* headNode=(struct Node*)malloc(sizeof(struct Node));
//变量的基本规则:使用前初始化
headNode->next=NULL;
return headNode;
}
//3.1.3创建节点(同创建表头):为插入做准备
//后面把用户的数据变为结构体变量
struct Node* createNode(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;
}
//第一次的删除写法
//问题:找删除节点和删除前一个节点
//函数名的Data为一个结构体
void deleteNodeByData(struct Node* headNode,Data) {
struct Node* posLeftNode = headNode;
struct Node* posNode=headNode->next;
//当查找的数据不是要删除的数据
while(posNode!=NULL && posNode->data!=Data) {
posLeftNode=posNode; //将左节点后移
posNode=posLeftNode->next; //将当前节点后移
}
//讨论查找结果
if(posNode==NULL)
return;
else {
posLeftNode->next=posNode->next;
free(posNode);
posNode=NULL;
}
}
//打印链表:以当前节点为头节点的链表
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;
}
}
3.2 数据结构设计
图书包含的信息可以自行添加,但要在对应的函数以及输出中进行相应的修改。
//3.2图书信息 书名、价格、数量
struct bookInfo {
char name[20];
float price;
int num;
};
4、文件操作
//4.文件操作-> 对 list
//4.1 存(写)操作
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); //关闭文件
}
//4.2 读操作
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);
}
5、排序(冒泡)
//5.使用价格排序 冒泡->相邻的相比较
void BubbleSortList(struct Node* headNode) {
struct Node* p;
struct Node* q;
for(p=headNode->next; p!=NULL; p=p->next) {
for(q=headNode->next; q->next!=NULL; q=q->next) {
if(q->data.price > q->data.price) {
struct bookInfo tempData=q->data;
q->data=q->next->data;
q->next->data=tempData;
}
}
}
printList(headNode);
}
6、查找
函数的定义类型即结构体指针,void无返回类型,不能用return。
//6.函数类型:结构体指针 -> 查找 -> 链表的查找
//借阅和归还使用查找功能写
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;
}
7、完整代码实现
无报错,可运行。
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
//3.数据设计(C自定义链表)
//3.2图书信息 书名、价格、数量
struct bookInfo {
char name[20];
float price;
int num;
};
struct Node* list=NULL;//全局链表
//3.1 链表 =结构体变量
//创建链表:
struct Node {
struct bookInfo data;
struct Node *next;
};
// 创建表头;表头就是结构体变量
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;
}
//指定位置删除posleft->next=pos->next and free(pos) and pso=NULL
//书名删除-> 字符串的删除,字符比较函数
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("删除成功!");
posLeftNode->next=posNode->next;
free(posNode);
posNode=NULL;
}
}
//6.函数类型:结构体指针 -> 查找 -> 链表的查找
//借阅和归还使用查找功能写
struct Node* searchByName(struct Node* headNode,char *bookname) {
struct Node* posNode=headNode->next;
//strcmp 0相等 >0前面的大 <0后面的大
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;
}
}
//1.make Menu-模块
void makeMenu() {
printf("+---------------------------------+\n");
printf("| Books Management System |\n");
printf("+---------------------------------+\n");
printf("0 退出系统\n");
printf("1 登记书籍\n");
printf("2 浏览书籍\n");
printf("3 借阅书籍\n");
printf("4 归还书籍\n");
printf("5 书籍排序\n");
printf("6 删除书籍\n");
printf("7 查找书籍\n\n");
printf("请选择(0~7):");
}
//4.文件操作-> 对 list
//4.1 存(写)操作
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); //关闭文件
}
//4.2 读操作
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);
}
//5.排序 冒泡->相邻的相比较
void BubbleSortList(struct Node* headNode) {
struct Node* p;
struct Node* q;
for(p=headNode->next; p!=NULL; p=p->next) {
for(q=headNode->next; q->next!=NULL; q=q->next) {
//价格排序
if(q->data.price > q->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");
exit(0);
break;
case 1:
printf("[登记]\n");
printf("请输入书籍信息:书名,价格,数量\n");
//字符串不用&
scanf("%s%f%d",tempBook.name, &tempBook.price, &tempBook.num);
insertNodeByHead(list,tempBook);
saveInfoToFile("bookInfo.txt",list);
break;
case 2:
printf("[浏览]\n");
printList(list);
break;
case 3:
printf("[借阅]\n");
printf("请输入借阅的书名:");
scanf("%s",tempBook.name);
result=searchByName(list,tempBook.name);
if(result==NULL) {
printf("目前没有该书,敬请期待!");
} else {
if(result->data.num>0) {
result->data.num--;
printf("借阅成功!\n");
} else {
printf("当前书籍无库存,无法借阅");
}
}
break;
case 4:
printf("[归还]\n");
printf("请输入归还的书名:");
scanf("%s",tempBook.name);
result=searchByName(list,tempBook.name);
if(result==NULL) {
printf("该书不属于本馆!");
} else {
result->data.num++;
printf("归还成功!\n");
}
break;
case 5:
printf("[排序]\n");
BubbleSortList(list);
break;
case 6:
printf("[删除]\n");
printf("请输入要删除的书名:");
scanf("%s",tempBook.name);
deleteNodeByName(list,tempBook.name);
//修改数据要同步到文件-> 保存到文件 -> 写文件
saveInfoToFile("bookIbgo.txt",list);
break;
case 7:
printf("[查找]\n");
printf("请输入要查找的书名:");
scanf("%s",tempBook.name);
result = searchByName(list,tempBook.name);
if(result==NULL) {
printf("查无此寻!");
} else {
printf("书名\t价格\t数量\n");
printf("%s\t%.1f\t%d\n",result->data.name,result->data.price,result->data.num);
}
break;
default:
printf("[Error! 请输入0~7之间的数字!]\n");
break;
}
}
int main() {
list = createHead(); //链表初始化
readInfoFromFile("bookinfo.txt",list);
while(1) {
makeMenu();
keyDown();
system("pause");
system("cls");
}
system("pause");
return 0;
}
8、学习笔记(含注释)
注释包含敲代码的过程以及简单的知识点记录。
#include<stdio.h> //input and outut
#include<stdlib.h> //strings
#include<string.h>
//3.数据设计(C自定义链表)
//3.1 先 程序用什么东西处理数据(数组、链表) ->用什么装数据
//3.2 在定义 数据结构
//3.3 另一部分 用户信息(未包含) C++
//图书管理、登录模块(获取用户基本信息)、用户管理(文件操作)
//#include<iostream>
//#include<list>
//using namespace std;
//struct student{
// char sname[20];
// char tel[20];
// int num;
// struct bookInfo userBook[3];
//};
//3.2图书信息 书名、价格、数量 -->修改节点data类型 and 打印 and 删除data类型
struct bookInfo {
char name[20];
float price;
int num;
};
struct Node* list=NULL;//全局链表
//3.1 链表 =结构体变量
//创建链表:
struct Node {
struct bookInfo data;
struct Node *next;
};
// 创建表头;表头就是结构体变量
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;
}
//插入:表头插入 1.让newnext指向下一个next 2. 头haednext->newNode(新节点)
void insertNodeByHead(struct Node* headNode,struct bookInfo data) {
struct Node* newNode=createNode(data);
newNode->next=headNode->next; //1
headNode->next=newNode; //2
}
//尾插pMove->next=NULL and oMove->next=newNode;
//void insertNodeByTail(struct Node* headNode,int data) {
// struct Node* pMove= headNode;
// while(pMove->next!=NULL) {
// pMove=pMove->next;
// }
// struct Node* newNode=createNode(data);
// pMove->next=newNode;
//}
//指定位置删除posleft->next=pos->next and free(pos) and pso=NULL
//书名删除-> 字符串的删除,字符比较函数
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("删除成功!");
posLeftNode->next=posNode->next;
free(posNode);
posNode=NULL;
}
}
//6.函数类型:结构体指针 -> 查找 -> 链表的查找
//借阅和归还使用查找功能写
struct Node* searchByName(struct Node* headNode,char *bookname) {
struct Node* posNode=headNode->next;
//strcmp 0相等 >0前面的大 <0后面的大
while(posNode!=NULL && strcmp(posNode->data.name,bookname)) {
posNode = posNode->next; //不相等
}
return posNode; //非空->找到了
}
//第一次的删除写法
//问题:找删除节点和删除前一个节点
//函数名的Data为一个结构体
//void deleteNodeByData(struct Node* headNode,struct bookInfo posData) {
// struct Node* posLeftNode = headNode;
// struct Node* posNode=headNode->next;
// //当查找的数据不是要删除的数据
// while(posNode!=NULL && posNode->data!=posData) {
// posLeftNode=posNode; //将左节点后移
// posNode=posLeftNode->next; //将当前节点后移
// }
// //讨论查找结果
// if(posNode==NULL)
// return;
// else {
// posLeftNode->next=posNode->next;
// free(posNode);
// posNode=NULL;
// }
//
//}
//打印链表:以当前节点为头节点的链表
void printList(struct Node* headNode) {
struct Node* pMove=headNode->next;
printf("书名\t价格\t数量\n");
while(pMove!=NULL) {
//剥洋葱方式显示
// printf("%d\t",pMove->data);
printf("%s\t%.1f\t%d\n",pMove->data.name, pMove->data.price, pMove->data.num);
pMove=pMove->next;
}
}
//1.make Menu-模块
void makeMenu() {
printf("+---------------------------------+\n");
printf("| Books Management System |\n");
printf("+---------------------------------+\n");
printf("0 退出系统\n");
printf("1 登记书籍\n"); //添加
printf("2 浏览书籍\n"); //显示
printf("3 借阅书籍\n"); //修改
printf("4 归还书籍\n");
printf("5 书籍排序\n");
printf("6 删除书籍\n"); //删除
printf("7 查找书籍\n\n"); //查询
printf("请选择(0~7):");
}
//4.文件操作-> 对 list
//const 定义常量,不允许被改变
//4.1 存(写)操作
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); //关闭文件
}
//4.2 读操作
void readInfoFromFile(const char *fileName,struct Node* headNode) {
FILE *fp=fopen(fileName,"r"); //只读
if(fp==NULL) {
//第一次打开 不存在就创建
fp=fopen(fileName,"w+");
}
//把文件当输入 name数组名本身表示取地址符
struct bookInfo tempData;
while(fscanf(fp,"%s\t%f\t%d\n",tempData.name,&tempData.price,&tempData.num)!=EOF) {
insertNodeByHead(list,tempData); //读一个信息插入链表
}
fclose(fp);
}
//5.排序 冒泡->相邻的相比较
void BubbleSortList(struct Node* headNode) {
struct Node* p;
struct Node* q;
for(p=headNode->next; p!=NULL; p=p->next) {
for(q=headNode->next; q->next!=NULL; q=q->next) {
//价格排序
if(q->data.price > q->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");
exit(0);
break;
case 1:
printf("[登记]\n");
printf("请输入书籍信息:书名,价格,数量\n");
//字符串不用&
scanf("%s%f%d",tempBook.name, &tempBook.price, &tempBook.num);
insertNodeByHead(list,tempBook);
saveInfoToFile("bookInfo.txt",list);
break;
case 2:
printf("[浏览]\n");
printList(list);
break;
case 3:
printf("[借阅]\n"); //书籍存在可借阅,数量-1;不存在,节约失败
printf("请输入借阅的书名:");
scanf("%s",tempBook.name);
result=searchByName(list,tempBook.name);
if(result==NULL) {
printf("目前没有该书,敬请期待!");
} else {
if(result->data.num>0) {
result->data.num--;
printf("借阅成功!\n");
} else {
printf("当前书籍无库存,无法借阅");
}
}
break;
case 4:
printf("[归还]\n"); //书籍数量+1
printf("请输入归还的书名:");
scanf("%s",tempBook.name);
result=searchByName(list,tempBook.name);
if(result==NULL) {
printf("该书不属于本馆!");
} else {
result->data.num++;
printf("归还成功!\n");
}
break;
case 5:
printf("[排序]\n");
BubbleSortList(list);
break;
case 6:
printf("[删除]\n");
printf("请输入要删除的书名:");
scanf("%s",tempBook.name);
deleteNodeByName(list,tempBook.name);
//修改数据要同步到文件-> 保存到文件 -> 写文件
saveInfoToFile("bookIbgo.txt",list);
break;
case 7:
printf("[查找]\n");
printf("请输入要查找的书名:");
scanf("%s",tempBook.name);
result = searchByName(list,tempBook.name);
if(result==NULL) {
printf("查无此寻!");
} else {
printf("书名\t价格\t数量\n");
printf("%s\t%.1f\t%d\n",result->data.name,result->data.price,result->data.num);
}
break;
default:
printf("[Error! 请输入0~7之间的数字!]\n");
break;
}
}
int main() {
//测试链表
// struct Node* list=creatHead();
// int i;
// for(i=0; i<3; i++) {
// insertNodeByHead(list,i); //前插
insertNodeByTail(list,i); //尾插
// }
deleteNodeByData(list,1); //删除
// printList(list);
list = createHead(); //链表初始化
readInfoFromFile("bookinfo.txt",list);
while(1) {
makeMenu();
keyDown();
system("pause");
system("cls");
}
system("pause");
return 0;
}
参考:
感谢大佬的细心录制!!!真的很清楚明白!
C/C++知识项目教程:图书管理系统!手把手教你写出大学C语言图书管理系统,简单易上手,大学C语言必会!_哔哩哔哩_bilibili