简单文件数据库-模拟图书馆管理系统-西安电子科技大学大一程序基础设计课程设计作业

2023-11-08

命令行参数如下:

Libsim –a(-u) xxxx

第一个参数为可执行程序名称;第二个参数为用户身份,-a表示管理员,-u表示读者;第三个参数为用户名

  • 问题分析:

由于无法直接在文件中插入数据(不是简单覆盖),固采用将文件数据提取为链表的方法,对链表进行操作,最后将链表信息导入文件中。

  1. 实现时的困难:
    1. 如何实现管理员和读者双菜单?
    2. 文件该以哪种方式打开?
    3. 文件信息读取不全是什么造成的?
    4. 操作后再读取文件出错,打开文件信息连在一起?
    5. 删除最后一个数据时出错?
    6. 如果用户输入的操作都无效(要修改的信息不存在)怎么办?
  2. 对应解决方案
    1. 判断命令行参数信息,用if判断语句分别进入功能即可。
    2. 操作者只需选择“r(只读)”和“a+(追加)”方式打开文件,防止文件数据意外损失。其中在只有管理员增加数据时才用“a+”,其他模式均以“r”方式打开!
    3. 因为程序有继续操作选项,而上次操作后文件标志已经为EOF,采用rewind函数即可将文件标志位重置
    4. 在写入、修改、删除信息时注意最后写入换行符,保证文件可读性以及下一次操作可行
    5. 因为采用的是链表操作,删除非末尾元素时,下一个链节内容完全拷贝到要删字节,再释放下一个链节即可。但是链表尾指向NULL,访问NULL会出错,要单独考虑。
    6. 定义变量int sign = 0;只有操作有效时sign = 1,进入下一步操作,防止文件信息丢失。
//程序基本配置文件: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;

}

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

简单文件数据库-模拟图书馆管理系统-西安电子科技大学大一程序基础设计课程设计作业 的相关文章

  • WPF DataGrid 多选

    我读过几篇关于这个主题的文章 但很多都是来自 VS 或框架的早期版本 我想做的是从 dataGrid 中选择多行并将这些行返回到绑定的可观察集合中 我尝试创建一个属性 类型 并将其添加到可观察集合中 它适用于单个记录 但代码永远不会触发多个
  • 如何将 std::string& 转换为 C# 引用字符串

    我正在尝试将 C 函数转换为std string参考C 我的 API 如下所示 void GetStringDemo std string str 理想情况下 我希望在 C 中看到类似的东西 void GetStringDemoWrap r
  • STL 迭代器:前缀增量更快? [复制]

    这个问题在这里已经有答案了 可能的重复 C 中的预增量比后增量快 正确吗 如果是 为什么呢 https stackoverflow com questions 2020184 preincrement faster than postinc
  • 在 xaml 中编写嵌套类型时出现设计时错误

    我创建了一个用户控件 它接受枚举类型并将该枚举的值分配给该用户控件中的 ComboBox 控件 很简单 我在数据模板中使用此用户控件 当出现嵌套类型时 问题就来了 我使用这个符号来指定 EnumType x Type myNamespace
  • 没有特殊字符的密码验证器

    我是 RegEx 的新手 已经进行了大量搜索 但没有找到任何具体内容 我正在编写一个验证密码字符串的正则表达式 可接受的字符串必须至少具有 4 种字符类型中的 3 种 数字 小写字母 大写字母 特殊字符 我对包含有一个想法 也就是说 如果这
  • C++11 删除重写方法

    Preface 这是一个关于最佳实践的问题 涉及 C 11 中引入的删除运算符的新含义 当应用于覆盖继承父类的虚拟方法的子类时 背景 根据标准 引用的第一个用例是明确禁止调用某些类型的函数 否则转换将是隐式的 例如最新版本第 8 4 3 节
  • 为什么 GCC 不允许我创建“内联静态 std::stringstream”?

    我将直接前往 MCVE include
  • 传递给函数时多维数组的指针类型是什么? [复制]

    这个问题在这里已经有答案了 我在大学课堂上学习了 C 语言和指针 除了多维数组和指针之间的相似性之外 我认为我已经很好地掌握了这个概念 我认为由于所有数组 甚至多维 都存储在连续内存中 因此您可以安全地将其转换为int 假设给定的数组是in
  • 如何使从 C# 调用的 C(P/invoke)代码“线程安全”

    我有一些简单的 C 代码 它使用单个全局变量 显然这不是线程安全的 所以当我使用 P invoke 从 C 中的多个线程调用它时 事情就搞砸了 如何为每个线程单独导入此函数 或使其线程安全 我尝试声明变量 declspec thread 但
  • 访问外部窗口句柄

    我当前正在处理的程序有问题 这是由于 vista Windows 7 中增强的安全性引起的 特别是 UIPI 它阻止完整性级别较低的窗口与较高完整性级别的窗口 对话 就我而言 我想告诉具有高完整性级别的窗口进入我们的应用程序 它在 XP 或
  • 在 Unity 中实现 Fur with Shells 技术

    我正在尝试在 Unity 中实现皮毛贝壳技术 http developer download nvidia com SDK 10 5 direct3d Source Fur doc FurShellsAndFins pdf Fins 技术被
  • 如何获取 EF 中与组合(键/值)列表匹配的记录?

    我有一个数据库表 其中包含每个用户 年份组合的记录 如何使用 EF 和用户 ID 年份组合列表从数据库获取数据 组合示例 UserId Year 1 2015 1 2016 1 2018 12 2016 12 2019 3 2015 91
  • WcfSvcHost 的跨域异常

    对于另一个跨域问题 我深表歉意 我一整天都在与这个问题作斗争 现在已经到了沸腾的地步 我有一个 Silverlight 应用程序项目 SLApp1 一个用于托管 Silverlight SLApp1 Web 的 Web 项目和 WCF 项目
  • 如何定义一个可结构化绑定的对象的概念?

    我想定义一个concept可以检测类型是否T can be 结构化绑定 or not template
  • 为什么 C# 2.0 之后没有 ISO 或 ECMA 标准化?

    我已经开始学习 C 并正在寻找标准规范 但发现大于 2 0 的 C 版本并未由 ISO 或 ECMA 标准化 或者是我从 Wikipedia 收集到的 这有什么原因吗 因为编写 审查 验证 发布 处理反馈 修订 重新发布等复杂的规范文档需要
  • C 编程:带有数组的函数

    我正在尝试编写一个函数 该函数查找行为 4 列为 4 的二维数组中的最大值 其中二维数组填充有用户输入 我知道我的主要错误是函数中的数组 但我不确定它是什么 如果有人能够找到我出错的地方而不是编写新代码 我将不胜感激 除非我刚去南方 我的尝
  • 对于某些 PDF 文件,LoadIFilter() 返回 -2147467259

    我正在尝试使用 Adob e IFilter 搜索 PDF 文件 我的代码是用 C 编写的 我使用 p invoke 来获取 IFilter 的实例 DllImport query dll SetLastError true CharSet
  • C++ 中的参考文献

    我偶尔会在 StackOverflow 上看到代码 询问一些涉及函数的重载歧义 例如 void foo int param 我的问题是 为什么会出现这种情况 或者更确切地说 你什么时候会有 对参考的参考 这与普通的旧参考有何不同 我从未在现
  • 在OpenGL中,我可以在坐标(5, 5)处精确地绘制一个像素吗?

    我所说的 5 5 正是指第五行第五列 我发现使用屏幕坐标来绘制东西非常困难 OpenGL 中的所有坐标都是相对的 通常范围从 1 0 到 1 0 为什么阻止程序员使用屏幕坐标 窗口坐标如此严重 最简单的方法可能是通过以下方式设置投影以匹配渲
  • 指针和内存范围

    我已经用 C 语言编程有一段时间了 但对 C 语言还是很陌生 有时我对 C 处理内存的方式感到困惑 考虑以下有效的 C 代码片段 const char string void where is this pointer variable l

随机推荐

  • Linux系统管理员非常使用的几款工具推荐

    1 ExplainShell com 命令解释 对于Linux用户来说每天都会写各种命令和脚本 那么你可以使用这个网站工具来查看命令式如何工作的 这样可以避免不必要的错误出现 也是一个很好的学习命令的方式 2 BashrcGenerator
  • 使用 Builder 构建对象

    遇到多个构造器参数时 要考虑使用构建器 当遇到成员变量较多的类时 使用构造方法初始化对象会使得代码的可读性以及规范性变差 比如想知道某个参数的含义时必须要查看构造方法的定义源码 而且如果不消息颠倒了参数的顺序 编译器可能也不会报错 可以使用
  • 【Java集合 4】java character

    Java学习路线 搬砖工逆袭Java架构师 简介 Java领域优质创作者 CSDN哪吒公众号作者 Java架构师奋斗者 扫描主页左侧二维码 加入群聊 一起学习 一起进步 欢迎点赞 收藏 留言 目录 一 前言 二 ASCII控制字符 三 AS
  • Oracle数据库的启动

    lsnrctl start 启动监听 sqlplus nolog SQL gt conn as sysdba SQL gt startup 启动数据
  • 提高性能 MSSQL百万数据量 值得注意的30条优化技巧

    1 对查询进行优化 应尽量避免全表扫描 首先应考虑在 where 及 order by 涉及的列上建立索引 2 应尽量避免在 where 子句中对字段进行 null 值判断 否则将导致引擎放弃使用索引而进行全表扫描 如 select id
  • JSP动态网页开发技术

    一 学习目标 1 JSP概述 2 JSP指令 3 JSP 隐式对象 二 重点知识 1 JSP概述 JSP是什么 1 JSP全称Java Server Pages 是一种动态网页开发技术 它使用JSP标签在HTML网页中插入Java代码 标签
  • android控制电脑,安卓手机远程控制电脑教程详解

    当我们出门在外 没有电脑在身边 但又急需远程处理电脑上的事务时 怎么办呢 自从锤子出了手机远程协助后 没有锤子的人就急了 这里有个可以让所有Android手机和ios手机实现远程协助功能的小技巧 能 远程控制 远程控制 远程控制 windo
  • 初始gensim

    1 import jieba 2 import gensim 3 from gensim import corpora 4 from gensim import models 5 from gensim import similaritie
  • 复制CSDN文章,去掉代码前面行号的方法(及一些正则表达式小技巧)

    分享一些平时工作中常用的正则表达式小技巧 一 去掉代码前面行号的方法 idongchen modify 2018 12 5 csdn的markdown解析器蛮恶心的文章整体复制下来总有行号在前面 可以用正则找到这些行号给去掉就好 带点的 s
  • sqli-labs(29-31)

    序 这三关都是双服务器问题 网上很多教程都只考虑了apache 其实是php apache jsp tomcat 环境的搭建已经写在了另外一篇博客中 这里再推荐一下一个大牛写得很好的博客 里面把每关的原理都讲得很清晰 但是他里面关于本关的原
  • CV-对比学习-模型:MoCo/SimCLR/BYOL/SimSiam

    很多大佬认为 深度学习的本质就是做两件事情 Representation Learning 表示学习 和 Inductive Bias Learning 归纳偏好学习 在表示学习方面 如果直接对语义进行监督学习 虽然表现很好 但是它需要很多
  • lvs负载均衡、LVS集群部署

    四 LVS集群部署 lvs给nginx做负载均衡项目 218lvs DR 负载均衡器 yum y install ipvsadm 安装这个工具来管理lvs 设置VIP192 168 142 120 创建ipvsadm的文件用来存放lvs的规
  • c语言 如何创建txt文件,C++文本文件读写操作详解

    前面章节中 已经给大家介绍了文件流对象如何调用 open 方法打开文件 并且在读写 又称 I O 文件操作结束后 应调用 close 方法关闭先前打开的文件 那么 如何实现对文件内容的读写呢 接下来就对此问题做详细的讲解 在讲解具体读写文件
  • MySQL基础---连接查询(等值连接与非等值连接)

    多个表格查询 笛卡尔乘积现象 表1有m行 表2 有n行 结果有m n行 发生原因在于没有有效的连接条件 如何避免 添加有效的连接条件 方法 分类方法 按照年代分类 sql192标准和sql199标准 功能 内链接 等值连接 非等值连接 自连
  • 学习日记——物联网云平台(乐鑫云平台)

    物联网云平台了解 1 物联网云平台 接收设备上报的数据 向设备下发数据 对数据进行转发 分析 计算 显示 管理设备等 2 常见的物联网云平台一般有 私有物联网云平台 假设某瓜农 为瓜棚装上了物联网温湿计 温湿度数据通过网络发送某台主机 这台
  • redis--11.1--操作--对列表类型,集合类型,有序集合类型进行键排序

    redis 11 1 操作 对列表类型 集合类型 有序集合类型进行键排序 1 命令 sort key alpha BY pattern LIMIT offset count GET pattern GET pattern asc desc
  • javax.validation.constraints注解

    文章目录 概要 常用的注解 其他注解 小结 概要 javax validation constraints是Java Validation API中的一个包 它提供了一组注解 用于在Java代码中进行数据校验和验证 该包中定义了多个注解 用
  • LR(1)分析表-语法树-四元式

    这学期的编译原理终于学完了 不愧是号称最难的科目 要用C 从头到尾实现一下小型编译器 还真不容易啊 不过总算是做完了 首先上文法 这个文法是根据上一篇博客简化的 但还是有一点问题的 暂时发现有一个地方不符合LR1的规则 函数的返回类型如果是
  • 【ACOUG】Oracle技术爱好者的乐园

    ACOUG 的含义为 All China Oracle User Group http www acoug org 该组织是为了更好的提供一个Oracle用户的交流和活动平台 组织和发起一些公益性质的活动 这个组织是Eygle和Kamus发
  • 简单文件数据库-模拟图书馆管理系统-西安电子科技大学大一程序基础设计课程设计作业

    命令行参数如下 Libsim a u xxxx 第一个参数为可执行程序名称 第二个参数为用户身份 a表示管理员 u表示读者 第三个参数为用户名 问题分析 由于无法直接在文件中插入数据 不是简单覆盖 固采用将文件数据提取为链表的方法 对链表进