命令行参数如下:
Libsim –a(-u) xxxx
第一个参数为可执行程序名称;第二个参数为用户身份,-a表示管理员,-u表示读者;第三个参数为用户名
- 问题分析:
由于无法直接在文件中插入数据(不是简单覆盖),固采用将文件数据提取为链表的方法,对链表进行操作,最后将链表信息导入文件中。
- 实现时的困难:
- 如何实现管理员和读者双菜单?
- 文件该以哪种方式打开?
- 文件信息读取不全是什么造成的?
- 操作后再读取文件出错,打开文件信息连在一起?
- 删除最后一个数据时出错?
- 如果用户输入的操作都无效(要修改的信息不存在)怎么办?
- 删除最后一个数据时出错?
- 操作后再读取文件出错,打开文件信息连在一起?
- 文件信息读取不全是什么造成的?
- 文件该以哪种方式打开?
- 如何实现管理员和读者双菜单?
- 对应解决方案
- 判断命令行参数信息,用if判断语句分别进入功能即可。
- 操作者只需选择“r(只读)”和“a+(追加)”方式打开文件,防止文件数据意外损失。其中在只有管理员增加数据时才用“a+”,其他模式均以“r”方式打开!
- 因为程序有继续操作选项,而上次操作后文件标志已经为EOF,采用rewind函数即可将文件标志位重置
- 在写入、修改、删除信息时注意最后写入换行符,保证文件可读性以及下一次操作可行
- 因为采用的是链表操作,删除非末尾元素时,下一个链节内容完全拷贝到要删字节,再释放下一个链节即可。但是链表尾指向NULL,访问NULL会出错,要单独考虑。
- 定义变量int sign = 0;只有操作有效时sign = 1,进入下一步操作,防止文件信息丢失。
- 因为采用的是链表操作,删除非末尾元素时,下一个链节内容完全拷贝到要删字节,再释放下一个链节即可。但是链表尾指向NULL,访问NULL会出错,要单独考虑。
- 在写入、修改、删除信息时注意最后写入换行符,保证文件可读性以及下一次操作可行
- 因为程序有继续操作选项,而上次操作后文件标志已经为EOF,采用rewind函数即可将文件标志位重置
- 操作者只需选择“r(只读)”和“a+(追加)”方式打开文件,防止文件数据意外损失。其中在只有管理员增加数据时才用“a+”,其他模式均以“r”方式打开!
- 判断命令行参数信息,用if判断语句分别进入功能即可。
//程序基本配置文件:1.文件名为“book.txt”的文件;2.文件名为“reader.txt”的文件
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
//测试方式选择:1.AUTO:命令行运行;2.标准文件流读入数据;3.手动输入输出数据(用哪个将另外两个#define注释掉即可)
//#define AUTO
//#define MANUAL1
#define MANUAL2
#define LEN1 sizeof(book_info)
#define LEN2 sizeof(reader_info)
//定义两个结构体,分别存储书本信息和读者借阅信息
typedef struct Book {
char code[20];
char title[100];
int number;
struct Book* next;
}book_info;
typedef struct Reader {
char order[20];
char name[100];
char borrow_code[20];
struct Reader* next;
}reader_info;
const char* book_format = “%s %s %d”, * reader_format = “%s %s %s”;
char file_name[101] = { 0 };
int main(int argc, char* argv[]) {
void format_judge(char* type, char* name);
FILE* open_file();
void function(char* type, char* name);
char type[3], name[100];
#ifdef AUTO
strcpy(type, argv[1]);
strcpy(name, argv[2]);
#endif
#ifdef MANUAL1
freopen(“in.txt”, “r”, stdin);
freopen(“out.txt”, “w”, stdout);
#endif
#ifdef MANUAL2
printf(“Enter user’s type(-a/-u) and username:\n”);
scanf(“%s %s”, type, name);
#endif
//输入参数格式正误判断
format_judge(type, name);
//操作函数
function(type, name);
return 0;
}
//打开文件函数
FILE* open_file() {
FILE* fp;
char ope_way[3] = { 0 };
//输入文件名和打开方式
printf("Enter the path of data:");
scanf("%s", file_name);
//*****注意操作者只需选择“r(只读)”和“a+(追加)”方式打开文件,防止文件数据意外损失!!!
printf("Enter the way to operate(r/a+):");
scanf("%s", ope_way);
//如果文件不存在,报错
if ((fp = fopen(file_name, ope_way)) == NULL) {
printf("File not exist\n");
exit(0);
}
return fp;
}
//显示文件的所有信息
void show_file(FILE* fp) {
if (fp == NULL) {
printf("File failed to open\n");
return;
}
//文件位置标志重置,以输出完整程序
rewind(fp);
char c;
//当文件位置为EOF(文件尾)
while (!feof(fp)) {
c = fgetc(fp);
printf("%c", c);
}
printf("\n");
}
//命令行输入参数判断
void format_judge(char* type, char* name) {
if (type[0] != '-' || (type[1] != 'a' && type[1] != 'u')) {
printf("Format Error!\n");
exit(0);
}
}
//覆盖文件函数,用于一次操作结束后将新文件内的数据覆盖到老文件上
//参数列表:指向原文件指针,指向操作产生的新文件的指针
void revise_file(FILE* fp, FILE* fp_n) {
if (fp_n == NULL) {
printf("New file failed to open\n");
return;
}
char c;
fclose(fp);
//以“w”方式打开文件,文件原内容擦除
fopen(file_name, "w");
rewind(fp_n);
//一个字符一个字符地拷贝到原文件中
while ((c = fgetc(fp_n)) != EOF) {
fputc(c, fp);
}
fclose(fp);
}
//功能集成函数
//参数列表:用户类型(-a:管理员/-u:用户);用户名
void function(char* type, char* name) {
FILE* open_file();
void add_info(FILE * fp, int object);
void revise_info(FILE * fp, int object);
void delete_info(FILE * fp, int object);
void borrow_book(FILE * fp, FILE * fp_r);
void return_book(FILE * fp_r);
void search_info(FILE * fp, FILE * fp_r);
//定义变量:1.option:操作类型;2.object:操作对象;3.sign:判断是否继续操作标志;4.fp:打开文件指针;5.fp_r:读者信息文件指针
int option, object, sign = 1;
FILE* fp = NULL, * fp_r = NULL;
//管理员模式
if (type[1] == 'a') {
printf("Administrator, what do you want to do\n\t1.Add information\n\t2.Revise information\n\t3.Delete information\n\t4.Show all the information\nOperate object:\n\t1.book\n\t2.reader\nAnswer:");
while (sign) {
scanf("%d%d", &option, &object);
//进入功能选择,详细见后面各功能函数
switch (option) {
case 1: //增加数据
{
fp = open_file();
add_info(fp, object);
break;
}
case 2: //修改数据
{
fp = open_file();
revise_info(fp, object);
break;
}
case 3: //删除数据
{
fp = open_file();
delete_info(fp, object);
break;
}
case 4: //总览数据
{
if (object == 1) {
fp = fopen("book.txt", "r");
show_file(fp);
}
else {
fp_r = fopen("reader.txt", "r");
show_file(fp_r);
}
break;
}
default:printf("Option Error\n");
}
//是否继续进行操作
printf("Continue to operate\n\t1->yes\n\t0->no\nAnswer:");
scanf("%d", &sign);
}
fclose(fp);
fclose(fp_r);
}
//用户模式
else {
printf("User, what do you want to do\n\t1.Borrow books\n\t2.Return books\n\t3.Search information\nAnswer:");
while (sign) {
scanf("%d", &option);
switch (option) {
case 1: //借书
{
fp = fopen("book.txt", "r");
fp_r = fopen("reader.txt", "a+");
if (fp == NULL || fp_r == NULL) {
printf("File missing\n");
}
else borrow_book(fp, fp_r);
break;
}
case 2: //还书
{
fp_r = fopen("reader.txt", "r+");
strcpy(file_name, "reader.txt\0");
if (fp_r == NULL) {
printf("File missing\n");
}
else return_book(fp_r);
break;
}
case 3: //查数据
{
fp = fopen("book.txt", "r");
fp_r = fopen("reader.txt", "r");
if (fp == NULL || fp_r == NULL) {
printf("File missing\n");
}
else search_info(fp, fp_r);
break;
}
default:printf("Option Error\n");
}
printf("Continue to operate\n\t1->yes\n\t0->no\nAnswer:");
scanf("%d", &sign);
}
fclose(fp);
}
}
//添加数据函数
//参数列表:指向操作文件的指针;操作对象
void add_info(FILE* fp, int object) {
if (fp == NULL) {
printf("File failed to open\n");
return;
}
//定义变量:1.num:操作次数;2.book:添加的图书信息的结构体;3.reader:添加的借阅信息结构体
int num;
book_info book;
reader_info reader;
//添加图书信息
if (object == 1) {
printf("How many books you want to add\nAnswer:");
scanf("%d", &num);
//提示输入图书信息的格式
printf("Information format:book_number title amount\nEnter:\n");
while (num--) {
scanf(book_format, &book.code, &book.title, &book.number);
fprintf(fp, book_format, book.code, book.title, book.number);
//*****注意添加完后换行!
fprintf(fp, "\n");
}
printf("Succeed to operate\n");
}
//添加借阅者信息
else if (object == 2) {
printf("How many readers you want to add\nAnswer:");
scanf("%d", &num);
printf("Information format:reader_number name book_code\nEnter:\n");
while (num--) {
scanf(reader_format, &reader.order, &reader.name, &reader.borrow_code);
fprintf(fp, reader_format, reader.order, reader.name, reader.borrow_code);
fprintf(fp, "\n");
}
printf("Succeed to operate\n");
}
else printf("Object error\n");
}
//修改数据函数
//参数列表:指向操作文件的指针;操作对象
void revise_info(FILE* fp, int object) {
if (fp == NULL) {
printf("File failed to open\n");
return;
}
rewind(fp);
book_info* original_information_input_b(FILE * fp);
reader_info* original_information_input_r(FILE * fp);
void information_save_b(book_info * head, FILE * fp_n);
void information_save_r(reader_info * head, FILE * fp_n);
book_info* get_adress_b(book_info * head_adress, char* search);
reader_info* get_adress_r(reader_info * head_adress, char* search);
void revise_file(FILE * fp, FILE * fp_n);
//定义变量:1.num:操作数;2.sign:操作是否有效标志;3.search:搜素信息(图书号或书名或读者编号或人名);4.fp_n:指向新文件(存贮操作后的信息)的指针
int num, sign = 0;
char search[100] = { 0 };
FILE* fp_n = NULL;
//修改图书信息
if (object == 1) {
//定义变量:1.head:存储了图书信息的链表头;2. book:存贮修改信息的结构体;3.locat:指向修改数据所在链节的指针
book_info* head = original_information_input_b(fp), book, * locat;
printf("How many books you want to revise\nAnswer:");
scanf("%d", &num);
while (num--) {
printf("Enter book_code or title:");
//输入要找的图书号或书名
scanf("%s", search);
//得到所在链表的位置,如果不存在,locat=NULL,不进行下列操作
locat = get_adress_b(head, search);
if (locat != NULL) {
printf("Enter the new information(Format:book_number title amount):");
//输入要用于替换的数据
scanf(book_format, &book.code, &book.title, &book.number);
strcpy(locat->code, book.code);
strcpy(locat->title, book.title);
locat->number = book.number;
//操作有效
sign = 1;
}
}
//如果输入的书本都不存在,即操作无效,不进行下列操作,防止书本信息文件内容被清空(revise_file函数有以“w”方式打开文件,文件内容清空)
if (sign) {
//打开存储修改信息的新文件“book_n.txt”
fp_n = fopen("book_n.txt", "w+");
//将链表信息存入新文件
information_save_b(head, fp_n);
//拷贝新文件中信息到原文件
revise_file(fp, fp_n);
printf("Succeed to operate\n");
}
}
if (object == 2) {
reader_info* head = original_information_input_r(fp), reader, * locat = head;
//确认是否修改找到信息(针对一个人借多本书的情况)
int answer;
printf("How many readers you want to revise\nAnswer:");
scanf("%d", &num);
while (num--) {
printf("Enter reader_order or name\n:");
scanf("%s", search);
while (locat != NULL) {
//*****得到该读者的第一条信息(注意搜索起点是locat,结合while循环实现搜索所有而非第一个出现的)!
locat = get_adress_r(locat, reader.order);
if (locat != NULL) {
//输出该条信息的内容
printf(reader_format, locat->order, locat->name, locat->borrow_code);
printf("\nRevise or not\n\t1.yes\n\t2.no\nAnswer:");
//确认是否修改该条信息
scanf("%d", &answer);
if (answer == 1) {
printf("Enter the new information(Format:reader_order name borrow_code):\n");
scanf(reader_format, &reader.order, &reader.name, &reader.borrow_code);
strcpy(locat->order, reader.order);
strcpy(locat->name, reader.name);
strcpy(locat->borrow_code, reader.borrow_code);
sign = 1;
}
//标记为指向下一个
locat = locat->next;
}
}
}
if (sign == 1) {
fp_n = fopen("reader_n.txt", "w+");
information_save_r(head, fp_n);
revise_file(fp, fp_n);
printf("Succeed to operate\n");
}
}
}
//删除数据函数
//参数列表:指向操作文件的指针;操作对象
void delete_info(FILE* fp, int object) {
if (fp == NULL) {
printf("File failed to open\n");
return;
}
rewind(fp);
book_info* original_information_input_b(FILE * fp);
reader_info* original_information_input_r(FILE * fp);
book_info* get_adress_b(book_info * head_adress, char* search);
reader_info* get_adress_r(reader_info * head_adress, char* search);
void information_save_b(book_info * head, FILE * fp_n);
void information_save_r(reader_info * head, FILE * fp_n);
void revise_file(FILE * fp, FILE * fp_n);
int num, answer, sign = 0;
char search[100];
if (object == 1) {
//定义变量:3.free_adress:指向要删除数据链节的指针
book_info* head = original_information_input_b(fp), * locat = NULL, * free_adress = NULL;
printf("How many books you want to delete\nAnswer:");
scanf("%d", &num);
while (num--) {
printf("Search book_code or title to delete:");
scanf("%s", search);
locat = get_adress_b(head, search);
//删除链节的方式采用复制——释放法,即将下一个链节内容完全拷贝到要删字节,再释放下一个链节
if (locat != NULL) {
//不是链表尾的情况
if (locat->next != NULL) {
free_adress = locat->next;
*locat = *(locat->next);
free(free_adress);
}
//*****链表尾的情况!(locat->next=NULL!访问会出错!)
else {
book_info* taget = head;
//找到要删链节的上一个链节
for (; taget->next != locat; taget = taget->next);
//将上一个链节的指向该为NULL,即可去除原先链表尾
taget->next = NULL;
free(locat);
}
sign = 1;
}
}
if (sign) {
FILE* fp_n = fopen("book_n.txt", "w+");
information_save_b(head, fp_n);
revise_file(fp, fp_n);
printf("Succeed to operate\n");
}
}
//删除读者信息,基本和修改读者信息部分相同
if (object == 2) {
reader_info* head = original_information_input_r(fp), * locat = head, * free_adress = NULL;
printf("How many readers you want to delete\nAnswer:");
scanf("%d", &num);
while (num--) {
printf("Search reader_order or name to delete:");
scanf("%s", search);
while (locat != NULL) {
locat = get_adress_r(locat, search);
if (locat != NULL) {
printf("This person's one record:");
printf(reader_format, locat->order, locat->name, locat->borrow_code);
printf("\nDelelt this record or not?\n\t1.yes\n\t2.no\nAnswer:");
scanf("%d", &answer);
if (answer == 1) {
if (locat->next != NULL) {
free_adress = locat->next;
*locat = *(locat->next);
free(free_adress);
}
else {
reader_info* taget = head;
for (; taget->next != locat; taget = taget->next);
taget->next = NULL;
free(locat);
}
sign = 1;
}
locat = locat->next;
}
}
}
if (sign) {
FILE* fp_n = fopen("reader_n.txt", "w+");
information_save_r(head, fp_n);
revise_file(fp, fp_n);
printf("Succeed to operate\n");
}
}
}
//借书函数
//参数列表:指向图书信息文件的指针;指向读者信息文件的指针
void borrow_book(FILE* fp, FILE* fp_r) {
if (fp == NULL || fp_r == NULL) {
printf("File failed to open\n");
return;
}
rewind(fp);
book_info* original_information_input_b(FILE * fp);
book_info* get_adress_b(book_info * head_adress, char* search);
int num, answer;
char search[100];
book_info* head = original_information_input_b(fp), * locat;
//询问是否列出馆藏图书列表
printf("Show book list\n\t1.yes\n\t2.no\nAnswer:");
scanf("%d", &answer);
if (answer == 1)show_file(fp);
printf("How many books you want to borrow\nAnswer:");
scanf("%d", &num);
while (num--) {
printf("Search book_code or title to borrow:");
scanf("%s", search);
locat = get_adress_b(head, search);
if (locat != NULL) {
char order[20], name[100];
printf("Enter your personal_order and your name:");
scanf("%s%s", order, name);
//将借阅信息存储到读者信息文件
fprintf(fp_r, reader_format, order, name, locat->code);
fprintf(fp_r, "\n");
printf("Succeed to operate\n");
}
}
}
//还书函数
//参数列表:指向读者信息文件的指针
void return_book(FILE* fp) {
if (fp == NULL) {
printf("File failed to open\n");
return;
}
rewind(fp);
reader_info* original_information_input_r(FILE * fp);
reader_info* get_adress_r(reader_info * head_adress, char* search);
void information_save_r(reader_info * head, FILE * fp_n);
int num, sign = 0;
reader_info reader, * head = original_information_input_r(fp), * locat = head;
printf("How many books you want to return\nAnswer:");
scanf("%d", &num);
while (num--) {
printf("Enter your person_order name and book_code:");
scanf(reader_format, reader.order, reader.name, reader.borrow_code);
//*****同时判断读者编号和姓名是否符合,直到链表尾 (注意下一次搜寻的起始地址为locat->next!)
for (; locat != NULL && strcmp(locat->order, reader.order) != 0; locat = get_adress_r(locat->next, reader.name));
if (locat != NULL) {
if (locat->next != NULL) {
reader_info* free_adress = locat->next;
*locat = *(locat->next);
free(free_adress);
}
else {
reader_info* taget = head;
for (; taget->next != locat; taget = taget->next);
taget->next = NULL;
free(locat);
}
sign = 1;
}
else printf("Record doesn't exist\n");
}
if (sign) {
FILE* fp_n = fopen("reader_n.txt", "w+");
information_save_r(head, fp_n);
revise_file(fp, fp_n);
printf("Succeed to operate\n");
}
}
//查数据函数
//参数列表:指向图书信息文件的指针;指向读者信息文件的指针
void search_info(FILE* fp, FILE* fp_r) {
book_info* original_information_input_b(FILE * fp);
reader_info* original_information_input_r(FILE * fp);
book_info* get_adress_b(book_info * head_adress, char* search);
reader_info* get_adress_r(reader_info * head_adress, char* search);
int answer, num, i = 1;
char search[100];
printf("Want to know what\n\t1.Show all books\n\t2.Search one book\n\t3.Remain to return\nAnswer:");
scanf("%d", &answer);
//展示所有馆藏图书
if (answer == 1) show_file(fp);
//输入图书号或书名看有没有
else if (answer == 2) {
book_info* head = original_information_input_b(fp);
printf("How many books you want to search\nAnswer:");
scanf("%d", &num);
while (num--) {
printf("Search book_code or title to show:");
scanf("%s", search);
book_info* locat = get_adress_b(head, search);
if (locat != NULL) {
printf(book_format, locat->code, locat->title, locat->number);
printf("\n");
reader_info* head_r = original_information_input_r(fp_r), * locat_r = head_r;
printf("Borrow record:\n");
for (i = 1; locat_r != NULL; locat_r = locat_r->next, i++) {
if (strcmp(locat->code, locat_r->borrow_code) == 0)
printf("%d : %s %s\n", i, locat_r->order, locat_r->name);
}
}
}
}
//输入个人信息查找待还图书
else if (answer == 3) {
reader_info reader, * head = original_information_input_r(fp_r), * locat = head;
printf("Enter your personal_order and name:");
scanf("%s%s", reader.order, reader.name);
while (locat != NULL) {
for (; locat != NULL && strcmp(locat->name, reader.name) != 0 && strcmp(locat->order, reader.order) != 0; locat = get_adress_r(locat->next, reader.order));
if (locat == NULL)break;
else {
printf("Borrowed book %d:", i++);
printf("%s", locat->borrow_code);
printf("\n");
locat = locat->next;
}
}
}
}
//创建链表函数,将图书信息文件提取成链表
//参数列表:指向图书信息文件指针;返回值:链表链头
book_info* original_information_input_b(FILE* fp) {
if (fp == NULL) {
printf("File failed to open\n");
return NULL;
}
//定义变量:1.head:链表头;2.当前链表操作位置指针;3.暂存数据的结构体
book_info* head = NULL, * p = NULL, temp;
int i = 0;
//从文件中读取信息直道文件尾
while (fscanf(fp, book_format, &temp.code, &temp.title, &temp.number) != EOF) {
i++;
//如果是链表头,开辟空间地址即为head,不是表头则依照赋值表达式的右结合性将链表进行延伸
if (i == 1)head = p = (book_info*)malloc(LEN1);
else p = p->next = (book_info*)malloc(LEN1);
strcpy(p->code, temp.code);
strcpy(p->title, temp.title);
p->number = temp.number;
}
//链表尾部处理
if (i != 0)p->next = NULL;
return head;
}
//创建链表函数,将读者信息文件提取成链表
//参数列表:指向读者信息文件指针 返回值:链表链头
reader_info* original_information_input_r(FILE* fp) {
if (fp == NULL) {
printf("File failed to open\n");
return NULL;
}
reader_info* head = NULL, * p = NULL, temp;
int i = 0;
while (fscanf(fp, reader_format, &temp.order, &temp.name, &temp.borrow_code) != EOF) {
i++;
if (i == 1)head = p = (reader_info*)malloc(LEN2);
else p = p->next = (reader_info*)malloc(LEN2);
strcpy(p->order, temp.order);
strcpy(p->name, temp.name);
strcpy(p->borrow_code, temp.borrow_code);
}
if (i != 0)p->next = NULL;
return head;
}
//保存链表信息函数,将图书信息链表保存到新文件中
//参数列表:指向图书信息新文件指针
void information_save_b(book_info* head, FILE* fp_n) {
book_info* p = head;
for (; p != NULL; p = p->next) {
fprintf(fp_n, book_format, p->code, p->title, p->number);
fprintf(fp_n, "\n");
}
}
//保存链表信息函数,将读者信息链表保存到新文件中
//参数列表:指向读者信息新文件指针
void information_save_r(reader_info* head, FILE* fp_n) {
reader_info* p = head;
for (; p != NULL; p = p->next) {
fprintf(fp_n, reader_format, p->order, p->name, p->borrow_code);
fprintf(fp_n, "\n");
}
}
//搜索信息函数
//参数列表:指向图书信息新文件指针 返回值:所找链节地址,无返回NULL
book_info* get_adress_b(book_info* head_adress, char* search) {
//定义变量:1.search_adress:当前搜索链节地址
book_info* search_adress = head_adress;
//先对图书号进行匹配,是否满足输入的信息
for (; search_adress != NULL && strcmp(search_adress->code, search) != 0; search_adress = search_adress->next);
//如果没有,重置当前搜索地址,再和书名进行匹配
if (search_adress == NULL) {
for (search_adress = head_adress; search_adress != NULL && strcmp(search_adress->title, search) != 0; search_adress = search_adress->next);
if (search_adress != NULL) return search_adress;
else {
printf("This book doesn't exist\n");
return NULL;
}
}
else return search_adress;
}
//搜索信息函数
//参数列表:指向读者信息新文件指针 返回值:所找链节地址,无返回NULL
reader_info* get_adress_r(reader_info* head_adress, char* search) {
reader_info* search_adress = head_adress;
for (; search_adress != NULL && strcmp(search_adress->order, search) != 0; search_adress = search_adress->next);
if (search_adress == NULL) {
for (search_adress = head_adress; search_adress != NULL && strcmp(search_adress->name, search) != 0; search_adress = search_adress->next);
if (search_adress != NULL) return search_adress;
else {
printf("This person doesn't exist\n");
return NULL;
}
}
else return search_adress;
}
本文转自 https://blog.csdn.net/qq_32971095/article/details/124508883,如有侵权,请联系删除。