通讯录的实现(静态版本和动态版本和文件版本)

news2024/11/16 9:19:57

为什们要实现通讯录?

主要是为了让我们将结构体的知识,了解的更加深刻,将结构体应用一下,我们先将静态的通讯录实现,在进行改良,用动态内存的知识再将通讯录改造一边,将动态内容的知识也运用一下,最后再用文件操作的方式在改造一下通讯录。
所以我们会写三个通讯录,同时他是循序渐进的,一步一步的,如果不动前面的知识,可以去看看前面的知识点。

  1. 静态版本通讯录
  2. 动态版本通讯录
  3. 文件版本通讯录

🐖静态通讯录

主要运用结构体的知识,不会的同学可以看看《自定义类型保姆级教学(结构体,位段,枚举,联合)》

首先先介绍一下代码的主题框架有三个部分test.c ,contact.c,contact.h
test.c的作用:测试通讯录的实现,也就是主函数,整个代码的操作逻辑
🐖contact.c的作用:写通讯录的实现(通讯录代码函数实现)
🐖contact.h的作用:写通讯录的声明(通讯录代码函数声明)

在引用头文件时需要注意的地方
🐖 contact.h中放通讯录的声明,在 test.ccontact.c的文件都要应用该声明,所以为什们我们不把 #include<stdio.h>这些头文件也放到声明里,我们就不需要在 test.ccontact.c的文件重复定义了,那么怎么在在 test.ccontact.c的文件中引用 contact.h文件呢,
🐕我们知道引用外部文件时,用双引号所以可以用 include"contact.h",这样在 contact.h中存放的声明都可以使用。

对于通讯录需要存放100个人的信息,每个人的信息包括(姓名,性别,电话,年龄,住址)
而且通讯录还要有以下功能,
🐶 (1)增加联系人
🐶 (2)删除指定联系人
🐶 (3)修改指定联系人
🐶 (4)查找指定联系人
🐶 (5)排序
🐶 (6)显示通讯录的信息

🍔通讯录的代码实现

🦊(1)通讯录的外部封装

对于通讯录不可能看完做完一个操作就不做了,所以应该写一个循环,能够选择要进行的操作,等操作做完,想要退出循环也是可以的,我们又知道,这个操作至少要进行一次,所以我们学过的循环发现只有do-while()循环可以用了,但对于通讯录来说他有很多操作,所以要用switch,case语句选择操作,但是又发现case后面只能跟整型表达式;所以要用一个菜单函数将这些操作与整型数字联系起来,比如在菜单函数中规定1-就是增加联系人,当switch选择1时就是增加联系人,
还需要注意一个点,也是在设计最巧妙的一个点,设置0的时候退出程序,在case后整型是0的时候break,然后到while()循环用0,就可以跳出循环,因为0为假。

在test.c 文件中写这个主函数

#include<stdio.h>
void menu()
{
	printf("***********************************\n");
	printf("****1-增加联系人   2-删除联系人****\n");
	printf("****3-修改联系人   4-查找联系人****\n");
	printf("****5-排序         6-显示通讯录****\n");
	printf("****       0-退出程序          ****\n");
	printf("***********************************\n");
}
int main()
{
	int input = 0;
	do
	{
		menu();
		printf("请选择操作->");
		scanf("%d", &input);
		switch(input)
		{
		case 1:
			break;
		case 2:
			break;
		case 3:
			break;
		case 4:
			break;
		case 5:
			break;
		case 6:
			break;
		case 0:
			printf("退出程序\n");
			break;
		default:
			printf("输入错误,请重新输入\n");
			break;
		}

	} while (input);
	return 0;
}

🦊(2)创建一个通讯录

<创建一个结构体>
🐖想要创建一个通讯录,就要创建一个结构体,用来表示一个人的信息(姓名,性别,电话,年龄,住址),通讯录中每个人的信息,而通讯录就想当与,众多人的集合,所以可以创建一个结构体数组。
🐕而对于这个表示一个人信息的结构体,因为也只是一个结构体,我们就放在通讯录声明的文件当中,也就是 contact.h文件。
//创建一个结构体,表示一个人的信息
struct PeoInf
{
	char name[20];
	char sex[20];
	char tele[12];
	int age;
	char addr[30];
};
<创建一个通讯录>
🐖创建好这个记录每个人信息的结构体,我们现在就可以创建通讯录了,而了解本质我们就知道,通讯录就是这个结构体数组。放到代码就是 struct PeoInf data[100];这样就创建了可以存放100个人信息的通讯录。
🐕但是大家觉得这样就完事了吗?那就大错特错了,这样想如果你想要增加一个信息,你要增加那个位置,你是不知道的,所以对于通讯录来说,我们不仅要创建这个数组,也要知道这个通讯录有几个信息,这时我们创建一个 int sz;来表示通讯录中有几个人的信息,所以将这两个内容再封装成一个结构体。代码如下,因为这是封装一个通讯录结构体,所以也放在 contact.h文件中。

有了通讯录的结构体,我们就可以在主函数中创建一个通讯录。

在这里插入图片描述

🦊(3)初始化通讯录

对于创建好了通讯录,对于通讯录的内容,应该先初始化,之后才可以进行修改。下面就要进行通讯录的初始化,注意他是传的是地址,不可以传值,如果传值,他是形参的一份临时拷贝,不会改变原本的参数,也就不能初始化。

void InitContact(struct Contact* pc)
{
	//防止是空指针,用断言函数
	assert(pc);
	pc->sz = 0;
	memset(pc->data, 0, 100 * sizeof(struct PeoInf));
}

🦊(4)增加通讯录(功能一:增)

代码实现,在代码中用注释解释,看完代码相信你就能理解了

//增加通讯录
void AddContact(struct Contact* pc)
{
	//防止是空指针,用断言函数
	assert(pc);
	//判断通讯录的信息满了没有,就是看sz的大小
	//if (pc->sz == 100)
	//我们发现这个100,我们一直再用,可以直接用define定义MAX=100
	//这时我们可以把通讯录中人的信息也用define定义
	if(pc -> sz == MAX)
	{
		printf("通讯录已满,无法增加数据\n"); 
		return;
		//因为通讯录已经放不下了,应该退出函数,对于这
		//个函数的返回值是void,所以不需要返回任何东西
	}
	else
	{
		printf("请输入名字:>");
		scanf("%s", pc->data[pc->sz].name);
		printf("请输入性别:>");
		scanf("%s", pc->data[pc->sz].sex);
		printf("请输入电话:>");
		scanf("%s", pc->data[pc->sz].tele);	
		printf("请输入年龄:>");
		scanf("%s", &(pc->data[pc->sz].age));
		printf("请输入地址:>");
		scanf("%s", pc->data[pc->sz].addr);
		pc->sz++;
		printf("成功增加联系人\n");
	}
}

🦊(5)查找通讯录(功能二:查)

跟增加通讯录一样,在注释中解释为什们要这么写

//显示通讯录的信息
void ShowContact(const struct Contact* pc)
{
	int i = 0;
	for (i = 0; i < pc->sz; i++)
	{
		printf("%s %s %s %d %s\n", pc->data[i].name,
			pc->data[i].sex,
			pc->data[i].tele,
			pc->data[i].age,
			pc->data[i].addr);
	}
}

在这里插入图片描述

上图,是我用上面的代码增加了三个人的信息然后查看,发现他们乱七八糟,每一个都没有一一对齐,连一个表头都没有,所以我们就要将这些代码对齐然后,在创建一个表头,请看下面代码。

//显示通讯录的信息
void ShowContact(const struct Contact* pc)
{
	int i = 0;
	printf("%-20s\t %-20s\t %-5s\t %-12s \t%-30s\n", "名字", "性别", "电话", "年龄", "地址");
	for (i = 0; i < pc->sz; i++)
	{
		printf("%-20s\t %-20s\t %-5s\t %-12d \t%-30s\n", pc->data[i].name,
			pc->data[i].sex,
			pc->data[i].tele,
			pc->data[i].age,
			pc->data[i].addr);
	}
}

在这里插入图片描述

🦊(6)删除通讯录-(功能三:删)

跟增加通讯录一样,在注释中解释为什们要这么写

}
//查找函数,通过名字找到这个人
int Findname(const struct Contact* pc, char name[])
{
	int i = 0;
	for (i = 0; i < pc->sz; i++)
	{
		if (0 == strcmp(pc->data[i].name, name))
		{
			return i;
		}
	}
	return -1;

}
//删除通讯录
void DelContact(struct Contact* pc)
{
	char name[NAME];
	printf("请输入删除人的名字:>");
	scanf("%s", name);
	//查找一下指定的人是否存在
	//就构造一个函数
	int ret = Findname(pc, name);
	if (ret == -1)
	{
		printf("要删除的人不存在\n");
	}
	else
	{
		//删除
		int j = 0;
		for (j = ret; j < pc->sz - 1 ; j++)
		{
			pc->data[j] = pc->data[j + 1];
		}
		pc->sz--;
		printf("成功删除联系人\n");
	}
}

🦊(7)查找通讯录-(功能三:查)

跟增加通讯录一样,在注释中解释为什们要这么写

//查找指定联系人
void SerchContact(const struct Contact* pc)
{
	//跟上面删除操作一样,只不过将删除变为查找
	char name[NAME];
	printf("请输入查找联系人的名字:>");
	scanf("%s", name);
	//查找一下查找的人是否存在
	//就会用上面的函数
	int ret = Findname(pc, name);
	if (ret == -1)
	{
		printf("要查找的人不存在\n");
	}
	else
	{
		//查找联系人,找到就打印出来
		printf("%-20s\t %-20s\t %-5s\t %-12s \t%-30s\n", "名字", "性别", "电话", "年龄", "地址");
		printf("%-20s\t %-20s\t %-5s\t %-12d \t%-30s\n", pc->data[ret].name,
			pc->data[ret].sex,
			pc->data[ret].tele,
			pc->data[ret].age,
			pc->data[ret].addr);
	}

🦊(8)修改通讯录-(功能三:改)

修改通讯录,就是先找到要修改的信息位置,然后再像增加通讯录一样重新录入一遍信息。

//修改指定联系人
void ModifyContact(struct Contact* pc)
{
	printf("请输入修改人的信息:>");
	char name[NAME];
	scanf("%s", name);
	int ret = Findname(pc, name);
	if (ret == -1)
	{
		printf("要查找的人不存在\n");
	}
	else
	{
		//修改
		//就相当于重新录入信息
		printf("请输入名字:>");
		scanf("%s", pc->data[ret].name);
		printf("请输入性别:>");
		scanf("%s", pc->data[ret].sex);
		printf("请输入电话:>");
		scanf("%s", pc->data[ret].tele);
		printf("请输入年龄:>");
		scanf("%d", &(pc->data[ret].age));
		printf("请输入地址:>");
		scanf("%s", pc->data[ret].addr);
		printf("修改成功\n");
	}
}

🦊(9)排序通讯录

要排序通讯录,就要学会使用qsort(可以在这个地方查找信息),我也写过一遍文章介绍这么用去sort函数《用冒泡排序模拟qsort库函数》,可以参考一下
在这里插入图片描述

下面代码是按年龄排序的,只要你将排序函数改一下内容就行了

//比较
int CmpByAge(const void* e1, const void* e2)
{
	return ((struct PeoInfo*)e1)->age - ((struct PeoInfo*)e2)->age;
}
//按照年龄来排序
void SortContact(struct Contact* pc)
{
	//用qsort排序
	qsort(pc->data, pc->sz, sizeof(struct PeoInfo), CmpByAge);
}

🦊(10)组装函数

我们将每个函数都写完了,但是运行起来需要在主函数中将这些函数串联起来,因此可以看下面的主函数的代码。

int main()
{
	//创建一个通讯录
	struct Contact con;
	//初始化通讯录
	InitContact(&con);
	int input = 0;
	do
	{
		menu();
		printf("请选择操作->");
		scanf("%d", &input);
		switch(input)
		{
		case 1:
			AddContact(&con);
			break;
		case 2:
			DelContact(&con);
			break;
		case 3:
			ModifyContact(&con);
			break;
		case 4:
			SerchContact(&con);
			break;
		case 5:
			SortContact(&con);
			break;
		case 6:
			ShowContact(&con);
			break;
		case 0:
			printf("退出程序\n");
			break;
		default:
			printf("输入错误,请重新输入\n");
			break;
		}

	} while (input);
	return 0;
}

🐕小总结

这样通讯录就写完了,看一看各各文件的代码吧

🦊test.c

#define _CRT_SECURE_NO_WARNINGS 1
#include"contact.h"
void menu()
{
	printf("***********************************\n");
	printf("****1-增加联系人   2-删除联系人****\n");
	printf("****3-修改联系人   4-查找联系人****\n");
	printf("****5-排序         6-显示通讯录****\n");
	printf("****       0-退出程序          ****\n");
	printf("***********************************\n");
}
int main()
{
	//创建一个通讯录
	struct Contact con;
	//初始化通讯录
	InitContact(&con);
	int input = 0;
	do
	{
		menu();
		printf("请选择操作->");
		scanf("%d", &input);
		switch(input)
		{
		case 1:
			AddContact(&con);
			break;
		case 2:
			DelContact(&con);
			break;
		case 3:
			ModifyContact(&con);
			break;
		case 4:
			SerchContact(&con);
			break;
		case 5:
			SortContact(&con);
			break;
		case 6:
			ShowContact(&con);
			break;
		case 0:
			printf("退出程序\n");
			break;
		default:
			printf("输入错误,请重新输入\n");
			break;
		}

	} while (input);
	return 0;
}

🦊contact.h

#pragma once
#include<stdio.h>
#include<string.h>
#define MAX 100
#define NAME 20
#define SEX 20
#define TELE 12
#define ADDR 30
#include<assert.h>
#include<stdlib.h>
struct PeoInfo
{
	char name[NAME];
	char sex[SEX];
	char tele[TELE];
	int age;
	char addr[ADDR];
};
//通讯录
struct Contact
{
	struct PeoInfo data[MAX];
	int sz ;
};
//初始化通讯录
void InitContact(struct Contact* pc);
//增加通讯录的信息
void AddContact(struct Contact* pc);
//显示通讯录的信息
void ShowContact(const struct Contact* pc);
//删除通讯录的信息
void DelContact(struct Contact *pc);
//查找指定联系人
void SerchContact(const struct Contact* pc);
//修改指定联系人
void ModifyContact(struct Contact* pc);
//排序通讯录-按照年龄
void SortContact(struct Constact* pc);


🦊 contact.c

#define _CRT_SECURE_NO_WARNINGS 1
#include"contact.h"

void InitContact(struct Contact* pc)
{
	//防止是空指针,用断言函数
	assert(pc);
	pc->sz = 0;
	memset(pc->data, 0, 100 * sizeof(struct PeoInfo));
}
//增加通讯录
void AddContact(struct Contact* pc)
{
	//防止是空指针,用断言函数
	assert(pc);
	//判断通讯录的信息满了没有,就是看sz的大小
	//if (pc->sz == 100)
	//我们发现这个100,我们一直再用,可以直接用define定义MAX=100
	//这时我们可以把通讯录中人的信息也用define定义
	if(pc -> sz == MAX)
	{
		printf("通讯录已满,无法增加数据\n"); 
		return;
		//因为通讯录已经放不下了,应该退出函数,对于这
		//个函数的返回值是void,所以不需要返回任何东西
	}
	else
	{
		printf("请输入名字:>");
		scanf("%s", pc->data[pc->sz].name);
		printf("请输入性别:>");
		scanf("%s", pc->data[pc->sz].sex);
		printf("请输入电话:>");
		scanf("%s", pc->data[pc->sz].tele);	
		printf("请输入年龄:>");
		scanf("%d", &(pc->data[pc->sz].age));
		printf("请输入地址:>");
		scanf("%s", pc->data[pc->sz].addr);
		pc->sz++;
		printf("成功增加联系人\n");
	}
}
//显示通讯录的信息
void ShowContact(const struct Contact* pc)
{
	int i = 0;
	printf("%-20s\t %-20s\t %-5s\t %-12s \t%-30s\n", "名字", "性别", "电话", "年龄", "地址");
	for (i = 0; i < pc->sz; i++)
	{
		printf("%-20s\t %-20s\t %-5s\t %-12d \t%-30s\n", pc->data[i].name,
			pc->data[i].sex,
			pc->data[i].tele,
			pc->data[i].age,
			pc->data[i].addr);
	}
}
//查找函数,通过名字找到这个人
static int Findname(const struct Contact* pc, char name[])
{
	int i = 0;
	for (i = 0; i < pc->sz; i++)
	{
		if (0 == strcmp(pc->data[i].name, name))
		{
			return i;
		}
	}
	return -1;

}
//删除通讯录
void DelContact(struct Contact* pc)
{
	char name[NAME];
	printf("请输入删除人的名字:>");
	scanf("%s", name);
	//查找一下指定的人是否存在
	//就构造一个函数
	int ret = Findname(pc, name);
	if (ret == -1)
	{
		printf("要删除的人不存在\n");
	}
	else
	{
		//删除
		int j = 0;
		for (j = ret; j < pc->sz - 1 ; j++)
		{
			pc->data[j] = pc->data[j + 1];
		}
		pc->sz--;
		printf("成功删除联系人\n");
	}
}
//查找指定联系人
void SerchContact(const struct Contact* pc)
{
	//跟上面删除操作一样,只不过将删除变为查找
	char name[NAME];
	printf("请输入查找联系人的名字:>");
	scanf("%s", name);
	//查找一下查找的人是否存在
	//就会用上面的函数
	int ret = Findname(pc, name);
	if (ret == -1)
	{
		printf("要查找的人不存在\n");
	}
	else
	{
		//查找联系人,找到就打印出来
		printf("%-20s\t %-20s\t %-5s\t %-12s \t%-30s\n", "名字", "性别", "电话", "年龄", "地址");
		printf("%-20s\t %-20s\t %-5s\t %-12d \t%-30s\n", pc->data[ret].name,
			pc->data[ret].sex,
			pc->data[ret].tele,
			pc->data[ret].age,
			pc->data[ret].addr);
	}
}
//修改指定联系人
void ModifyContact(struct Contact* pc)
{
	printf("请输入修改人的信息:>");
	char name[NAME];
	scanf("%s", name);
	int ret = Findname(pc, name);
	if (ret == -1)
	{
		printf("要查找的人不存在\n");
	}
	else
	{
		//修改
		//就相当于重新录入信息
		printf("请输入名字:>");
		scanf("%s", pc->data[ret].name);
		printf("请输入性别:>");
		scanf("%s", pc->data[ret].sex);
		printf("请输入电话:>");
		scanf("%s", pc->data[ret].tele);
		printf("请输入年龄:>");
		scanf("%d", &(pc->data[ret].age));
		printf("请输入地址:>");
		scanf("%s", pc->data[ret].addr);
		printf("修改成功\n");
	}
}
//比较
int CmpByAge(const void* e1, const void* e2)
{
	return ((struct PeoInfo*)e1)->age - ((struct PeoInfo*)e2)->age;
}
//按照年龄来排序
void SortContact(struct Contact* pc)
{
	//用qsort排序
	qsort(pc->data, pc->sz, sizeof(struct PeoInfo), CmpByAge);
}

🐖动态通讯录

主要运用动态内存开辟的知识,不会的同学可以看看《动态内存管理(malloc free calloc realloc)》

(1)为什们要设计动态通讯录
起始就是在静态通讯录上改造,并且对于动态开辟空间的函数的运用。
静态通讯只能存放100个人,但是这样就不够灵活,为了让通讯录可以更加灵活,就设计成动态通讯录
(2)设计动态通讯录的思路
首先先做一个通讯录,用 malloc存放3个人空间,存放满了后,在用 realloc增加两个人的空间,这样就更加灵活,并且不会浪费空间。
对于这个我们创建通讯录的代码就要改变,因为 malloc创建的空间用 void*指针来接收,所以将 data[]变为指针,并且在多增加一个参数,容量参数 capacity,当 szcapacity相同时,增加2个空间。所以

🍔动态通讯录代码实现

🦊(1)创建通讯录的代码如下:

🐖

//通讯录
struct Contact
{
	struct PeoInfo *data ;
	int sz;
	int capacity;
};

🦊(2)初始化通讯录

初始化通讯录,用malloc申请3个结构体的空间

void InitContact(struct Contact* pc)
{
	//防止是空指针,用断言函数
	assert(pc);
	pc->data = (struct PeoInfo*)malloc(sizeof(struct PeoInfo) * 3);
	if (pc == NULL)
	{
		peeor("InitContact");
		return;
	}
	else
	{
		pc -> sz = 0;
		//pc->capacity = 3;
		//我们发现这个3,我们一直再用,可以直接用define定义Capacity = 3
		//这时我们可以把通讯录中人的信息也用define定义
		pc->capacity = CAPATICY;

	}
}

🦊(3)增加通讯录

对于增加那用不用改呢,答案是用的,因为当空间不够的时候就需要增加空间。

int check_capacity(struct Contact* pc)
{
	if (pc->sz == pc->capacity)
	{
		//当前容量满了,现在用realloc增加容量
		struct PeoInfo* str = (struct PeoInfo*)relloc(pc->data, (pc->capacity + 2) * sizeof(struct PeoInfo));
		if (str == NULL)
		{
			printf("空间申请失败\n");
			return 0;
		}
		else
		{
			pc->data = str;
			//将申请的空间传给pc->data	
			pc->capacity = pc->capacity + 2;
			//将容量变大2.
			printf("增容成功\n");
			return 1;
		}
	}
	return 1;
}

//增加通讯录
void AddContact(struct Contact* pc)
{
	//防止是空指针,用断言函数
	assert(pc);
	//判断通讯录的信息满了没有,就是看sz的大小
	//if (pc->sz == 100)
	//我们发现这个100,我们一直再用,可以直接用define定义MAX=100
	//这时我们可以把通讯录中人的信息也用define定义

	//我们可以封装一个函数来判断他是否需要增容
	
	int ret = check_capacity(pc);

	if (ret == 1)
	{
		printf("请输入名字:>");
		scanf("%s", pc->data[pc->sz].name);
		printf("请输入性别:>");
		scanf("%s", pc->data[pc->sz].sex);
		printf("请输入电话:>");
		scanf("%s", pc->data[pc->sz].tele);
		printf("请输入年龄:>");
		scanf("%d", &(pc->data[pc->sz].age));
		printf("请输入地址:>");
		scanf("%s", pc->data[pc->sz].addr);
		pc->sz++;
		printf("成功增加联系人\n");
	}
	else
	{
		return;
	}
}

🦊(4)销毁通讯录

我们知道callocfree是同时出现的,申请了空间,就肯定要销毁空间,所以在退出函数就可以添加一个函数,销毁函数。

void DistoryContact(struct Contact* pc) 
{
	free(pc->data);
	pc->data = NULL;
	pc->capacity = 0;
	pc->sz = 0;
}

🐕动态总结

动态开辟内存还是相对与来说比较简单的,希望大家先将动态内存的知识看懂,再将动态通讯录来练习学会。

🦊动态test.c

#define _CRT_SECURE_NO_WARNINGS 1
#define _CRT_SECURE_NO_WARNINGS 1
#include"contact.h"
void menu()
{
	printf("***********************************\n");
	printf("****1-增加联系人   2-删除联系人****\n");
	printf("****3-修改联系人   4-查找联系人****\n");
	printf("****5-排序         6-显示通讯录****\n");
	printf("****       0-退出程序          ****\n");
	printf("***********************************\n");
}
int main()
{
	//创建一个通讯录
	struct Contact con;
	//初始化通讯录
	InitContact(&con);
	int input = 0;
	do
	{
		menu();
		printf("请选择操作->");
		scanf("%d", &input);
		switch (input)
		{
		case 1:
			AddContact(&con);
			break;
		case 2:
			DelContact(&con);
			break;
		case 3:
			ModifyContact(&con);
			break;
		case 4:
			SerchContact(&con);
			break;
		case 5:
			SortContact(&con);
			break;
		case 6:
			ShowContact(&con);
			break;
		case 0:
			DistoryContact(&con);
			printf("退出程序\n");
			break;
		default:
			printf("输入错误,请重新输入\n");
			break;
		}

	} while (input);
	return 0;
}
🦊动态contact.h
#pragma once
#pragma once
#include<stdio.h>
#include<string.h>
#define MAX 100
#define NAME 20
#define SEX 20
#define TELE 12
#define ADDR 30
#include<assert.h>
#include<stdlib.h>
#define CAPATICY 3
struct PeoInfo
{
	char name[NAME];
	char sex[SEX];
	char tele[TELE];
	int age;
	char addr[ADDR];
};
//通讯录
struct Contact
{
	struct PeoInfo *data ;
	int sz;
	int capacity;
};
//初始化通讯录
void InitContact(struct Contact* pc);
//增加通讯录的信息
void AddContact(struct Contact* pc);
//显示通讯录的信息
void ShowContact(const struct Contact* pc);
//删除通讯录的信息
void DelContact(struct Contact* pc);
//查找指定联系人
void SerchContact(const struct Contact* pc);
//修改指定联系人
void ModifyContact(struct Contact* pc);
//排序通讯录-按照年龄
void SortContact(struct Contact* pc);
//销毁通讯录
void DistoryContact(struct Contact*pc);

🦊动态contact.c

#define _CRT_SECURE_NO_WARNINGS 1
#define _CRT_SECURE_NO_WARNINGS 1
#include"contact.h"

void InitContact(struct Contact* pc)
{
	//防止是空指针,用断言函数
	assert(pc);
	pc->data = (struct PeoInfo*)malloc(sizeof(struct PeoInfo) * 3);
	if (pc == NULL)
	{
		perror("InitContact");
		return;
	}
	else
	{
		pc -> sz = 0;
		//pc->capacity = 3;
		//我们发现这个3,我们一直再用,可以直接用define定义Capacity = 3
		//这时我们可以把通讯录中人的信息也用define定义
		pc->capacity = CAPATICY;

	}
}
int check_capacity(struct Contact* pc)
{
	if (pc->sz == pc->capacity)
	{
		//当前容量满了,现在用realloc增加容量
		struct PeoInfo* str = (struct PeoInfo*)realloc(pc->data, (pc->capacity + 2) * sizeof(struct PeoInfo));
		if (str == NULL)
		{
			printf("空间申请失败\n");
			return 0;
		}
		else
		{
			pc->data = str;
			//将申请的空间传给pc->data	
			pc->capacity = pc->capacity + 2;
			//将容量变大2.
			printf("增容成功\n");
			return 1;
		}
	}
	return 1;
}

//增加通讯录
void AddContact(struct Contact* pc)
{
	//防止是空指针,用断言函数
	assert(pc);
	//判断通讯录的信息满了没有,就是看sz的大小
	//if (pc->sz == 100)
	//我们发现这个100,我们一直再用,可以直接用define定义MAX=100
	//这时我们可以把通讯录中人的信息也用define定义

	//我们可以封装一个函数来判断他是否需要增容
	
	int ret = check_capacity(pc);

	if (ret == 1)
	{
		printf("请输入名字:>");
		scanf("%s", pc->data[pc->sz].name);
		printf("请输入性别:>");
		scanf("%s", pc->data[pc->sz].sex);
		printf("请输入电话:>");
		scanf("%s", pc->data[pc->sz].tele);
		printf("请输入年龄:>");
		scanf("%d", &(pc->data[pc->sz].age));
		printf("请输入地址:>");
		scanf("%s", pc->data[pc->sz].addr);
		pc->sz++;
		printf("成功增加联系人\n");
	}
	else
	{
		return;
	}
}
//显示通讯录的信息
void ShowContact(const struct Contact* pc)
{
	int i = 0;
	printf("%-20s\t %-20s\t %-5s\t %-12s \t%-30s\n", "名字", "性别", "电话", "年龄", "地址");
	for (i = 0; i < pc->sz; i++)
	{
		printf("%-20s\t %-20s\t %-5s\t %-12d \t%-30s\n", pc->data[i].name,
			pc->data[i].sex,
			pc->data[i].tele,
			pc->data[i].age,
			pc->data[i].addr);
	}
}
//查找函数,通过名字找到这个人
static int Findname(const struct Contact* pc, char name[])
{
	int i = 0;
	for (i = 0; i < pc->sz; i++)
	{
		if (0 == strcmp(pc->data[i].name, name))
		{
			return i;
		}
	}
	return -1;

}
//删除通讯录
void DelContact(struct Contact* pc)
{
	char name[NAME];
	printf("请输入删除人的名字:>");
	scanf("%s", name);
	//查找一下指定的人是否存在
	//就构造一个函数
	int ret = Findname(pc, name);
	if (ret == -1)
	{
		printf("要删除的人不存在\n");
	}
	else
	{
		//删除
		int j = 0;
		for (j = ret; j < pc->sz - 1; j++)
		{
			pc->data[j] = pc->data[j + 1];
		}
		pc->sz--;
		printf("成功删除联系人\n");
	}
}
//查找指定联系人
void SerchContact(const struct Contact* pc)
{
	//跟上面删除操作一样,只不过将删除变为查找
	char name[NAME];
	printf("请输入查找联系人的名字:>");
	scanf("%s", name);
	//查找一下查找的人是否存在
	//就会用上面的函数
	int ret = Findname(pc, name);
	if (ret == -1)
	{
		printf("要查找的人不存在\n");
	}
	else
	{
		//查找联系人,找到就打印出来
		printf("%-20s\t %-20s\t %-5s\t %-12s \t%-30s\n", "名字", "性别", "电话", "年龄", "地址");
		printf("%-20s\t %-20s\t %-5s\t %-12d \t%-30s\n", pc->data[ret].name,
			pc->data[ret].sex,
			pc->data[ret].tele,
			pc->data[ret].age,
			pc->data[ret].addr);
	}
}
//修改指定联系人
void ModifyContact(struct Contact* pc)
{
	printf("请输入修改人的信息:>");
	char name[NAME];
	scanf("%s", name);
	int ret = Findname(pc, name);
	if (ret == -1)
	{
		printf("要查找的人不存在\n");
	}
	else
	{
		//修改
		//就相当于重新录入信息
		printf("请输入名字:>");
		scanf("%s", pc->data[ret].name);
		printf("请输入性别:>");
		scanf("%s", pc->data[ret].sex);
		printf("请输入电话:>");
		scanf("%s", pc->data[ret].tele);
		printf("请输入年龄:>");
		scanf("%d", &(pc->data[ret].age));
		printf("请输入地址:>");
		scanf("%s", pc->data[ret].addr);
		printf("修改成功\n");
	}
}
//比较
int CmpByAge(const void* e1, const void* e2)
{
	return ((struct PeoInfo*)e1)->age - ((struct PeoInfo*)e2)->age;
}
//按照年龄来排序
void SortContact(struct Contact* pc)
{
	//用qsort排序
	qsort(pc->data, pc->sz, sizeof(struct PeoInfo), CmpByAge);
}
void DistoryContact(struct Contact* pc) 
{
	free(pc->data);
	pc->data = NULL;
	pc->capacity = 0;
	pc->sz = 0;
}

🐖文件通讯录

主要运用文件操作的知识,不会的同学可以看看《C的文件操作》

文件通讯录的需求
通讯录退出后,之前保存的信息不能改变,当下一次重新运行通讯录的时候,还能看到上次保存的信息
分析需求
退出的时候,把数据保存到文件中,当下一次运行的时候,再从文件中加载信息就可以了

🍔文件通讯录代码实现

🦊保存通讯录

首先我们要实现这个需求,在退出之前,保存通讯录。

//保存通讯录
void SaveContact(struct Contact* pc)
{
	//打开文件,用二进制的方式写
	FILE* tt = fopen("Contact.txt", "wb");
	//判断是否为空指针
	if (tt == NULL)
	{
		perror("SaveContact:fopen");
		return;
	}
	//可以写了
	for (int i = 0; i < pc->sz; i++)
	{
		fwrite(pc->data + i, sizeof(struct PeoInfo), 1, tt);
	}

	//关闭文件
	fclose(tt);
	tt = NULL;
	return 0;
}

🦊加载通讯录

⭐将通讯录保存了,但是在打开通讯录的时候,需要能够读取文件的信息,但是这个操作在哪进行呀,我们可以在初始化通讯录的时候进行读取文件的信息操作。

static int check_capacity(struct Contact* pc);

void loadContact(struct Contact* pc)
{
	//打开文件
	FILE* tt = fopen("Contact.txt", "rb");
	if (tt == NULL)
	{
		perror("loadContact:fopen");
		return;
	}
	//读文件
	//创建一个临时结构体,当中介
	struct PeoInfo tmp = { 0 };
	//因为这是动态版本,可能涉及到增容问题
	//用他的返回值看,读取失败返回0;
	while (fread(&tmp, sizeof(struct PeoInfo), 1, tt))
	{
		//考虑增容问题
		check_capacity(pc);
		pc->data[pc->sz] = tmp;
		pc->sz++;
	}
	//关闭文件
}

🦊文件test.c

文件的代码其实大致无差,就是多了这个功能,为了以防万一还是放在这里了。欢迎大家食用。

#define _CRT_SECURE_NO_WARNINGS 1
#define _CRT_SECURE_NO_WARNINGS 1
#include"contact.h"
void menu()
{
	printf("***********************************\n");
	printf("****1-增加联系人   2-删除联系人****\n");
	printf("****3-修改联系人   4-查找联系人****\n");
	printf("****5-排序         6-显示通讯录****\n");
	printf("****       0-退出程序          ****\n");
	printf("***********************************\n");
}
int main()
{
	//创建一个通讯录
	struct Contact con;
	//初始化通讯录
	InitContact(&con);
	int input = 0;
	do
	{
		menu();
		printf("请选择操作->");
		scanf("%d", &input);
		switch (input)
		{
		case 1:
			AddContact(&con);
			break;
		case 2:
			DelContact(&con);
			break;
		case 3:
			ModifyContact(&con);
			break;
		case 4:
			SerchContact(&con);
			break;
		case 5:
			SortContact(&con);
			break;
		case 6:
			ShowContact(&con);
			break;
		case 0:
			SaveContact(&con);
			DistoryContact(&con);
			printf("退出程序\n");
			break;
		default:
			printf("输入错误,请重新输入\n");
			break;
		}

	} while (input);
	return 0;
}
🦊文件contact.h
#pragma once
#pragma once
#include<stdio.h>
#include<string.h>
#define MAX 100
#define NAME 20
#define SEX 20
#define TELE 12
#define ADDR 30
#include<assert.h>
#include<stdlib.h>
#define CAPATICY 3
struct PeoInfo
{
	char name[NAME];
	char sex[SEX];
	char tele[TELE];
	int age;
	char addr[ADDR];
};
//通讯录
struct Contact
{
	struct PeoInfo *data ;
	int sz;
	int capacity;
};
//初始化通讯录
void InitContact(struct Contact* pc);
//增加通讯录的信息
void AddContact(struct Contact* pc);
//显示通讯录的信息
void ShowContact(const struct Contact* pc);
//删除通讯录的信息
void DelContact(struct Contact* pc);
//查找指定联系人
void SerchContact(const struct Contact* pc);
//修改指定联系人
void ModifyContact(struct Contact* pc);
//排序通讯录-按照年龄
void SortContact(struct Contact* pc);
//销毁通讯录
void DistoryContact(struct Contact*pc);
//保存通讯录
void SaveContact(struct Contact* pc);

🦊动态contact.c

#define _CRT_SECURE_NO_WARNINGS 1
#define _CRT_SECURE_NO_WARNINGS 1
#include"contact.h"
static int check_capacity(struct Contact* pc);

void loadContact(struct Contact* pc)
{
	//打开文件
	FILE* tt = fopen("Contact.txt", "rb");
	if (tt == NULL)
	{
		perror("loadContact:fopen");
		return;
	}
	//读文件
	//创建一个临时结构体,当中介
	struct PeoInfo tmp = { 0 };
	//因为这是动态版本,可能涉及到增容问题
	//用他的返回值看,读取失败返回0;
	while (fread(&tmp, sizeof(struct PeoInfo), 1, tt))
	{
		//考虑增容问题
		check_capacity(pc);
		pc->data[pc->sz] = tmp;
		pc->sz++;
	}
	//关闭文件
}
void InitContact(struct Contact* pc)
{
	//防止是空指针,用断言函数
	assert(pc);
	pc->data = (struct PeoInfo*)malloc(sizeof(struct PeoInfo) * 3);
	if (pc == NULL)
	{
		perror("InitContact");
		return;
	}
	else
	{
		pc -> sz = 0;
		//pc->capacity = 3;
		//我们发现这个3,我们一直再用,可以直接用define定义Capacity = 3
		//这时我们可以把通讯录中人的信息也用define定义
		pc->capacity = CAPATICY;

	}
	//加载通讯录,让文件的信息加载到通讯录
	loadContact(pc);
}
static int check_capacity(struct Contact* pc)
{
	if (pc->sz == pc->capacity)
	{
		//当前容量满了,现在用realloc增加容量
		struct PeoInfo* str = (struct PeoInfo*)realloc(pc->data, (pc->capacity + 2) * sizeof(struct PeoInfo));
		if (str == NULL)
		{
			printf("空间申请失败\n");
			return 0;
		}
		else
		{
			pc->data = str;
			//将申请的空间传给pc->data	
			pc->capacity = pc->capacity + 2;
			//将容量变大2.
			printf("增容成功\n");
			return 1;
		}
	}
	return 1;
}

//增加通讯录
void AddContact(struct Contact* pc)
{
	//防止是空指针,用断言函数
	assert(pc);
	//判断通讯录的信息满了没有,就是看sz的大小
	//if (pc->sz == 100)
	//我们发现这个100,我们一直再用,可以直接用define定义MAX=100
	//这时我们可以把通讯录中人的信息也用define定义

	//我们可以封装一个函数来判断他是否需要增容
	
	int ret = check_capacity(pc);

	if (ret == 1)
	{
		printf("请输入名字:>");
		scanf("%s", pc->data[pc->sz].name);
		printf("请输入性别:>");
		scanf("%s", pc->data[pc->sz].sex);
		printf("请输入电话:>");
		scanf("%s", pc->data[pc->sz].tele);
		printf("请输入年龄:>");
		scanf("%d", &(pc->data[pc->sz].age));
		printf("请输入地址:>");
		scanf("%s", pc->data[pc->sz].addr);
		pc->sz++;
		printf("成功增加联系人\n");
	}
	else
	{
		return;
	}
}
//显示通讯录的信息
void ShowContact(const struct Contact* pc)
{
	int i = 0;
	printf("%-20s\t %-20s\t %-5s\t %-12s \t%-30s\n", "名字", "性别", "电话", "年龄", "地址");
	for (i = 0; i < pc->sz; i++)
	{
		printf("%-20s\t %-20s\t %-5s\t %-12d \t%-30s\n", pc->data[i].name,
			pc->data[i].sex,
			pc->data[i].tele,
			pc->data[i].age,
			pc->data[i].addr);
	}
}
//查找函数,通过名字找到这个人
static int Findname(const struct Contact* pc, char name[])
{
	int i = 0;
	for (i = 0; i < pc->sz; i++)
	{
		if (0 == strcmp(pc->data[i].name, name))
		{
			return i;
		}
	}
	return -1;

}
//删除通讯录
void DelContact(struct Contact* pc)
{
	char name[NAME];
	printf("请输入删除人的名字:>");
	scanf("%s", name);
	//查找一下指定的人是否存在
	//就构造一个函数
	int ret = Findname(pc, name);
	if (ret == -1)
	{
		printf("要删除的人不存在\n");
	}
	else
	{
		//删除
		int j = 0;
		for (j = ret; j < pc->sz - 1; j++)
		{
			pc->data[j] = pc->data[j + 1];
		}
		pc->sz--;
		printf("成功删除联系人\n");
	}
}
//查找指定联系人
void SerchContact(const struct Contact* pc)
{
	//跟上面删除操作一样,只不过将删除变为查找
	char name[NAME];
	printf("请输入查找联系人的名字:>");
	scanf("%s", name);
	//查找一下查找的人是否存在
	//就会用上面的函数
	int ret = Findname(pc, name);
	if (ret == -1)
	{
		printf("要查找的人不存在\n");
	}
	else
	{
		//查找联系人,找到就打印出来
		printf("%-20s\t %-20s\t %-5s\t %-12s \t%-30s\n", "名字", "性别", "电话", "年龄", "地址");
		printf("%-20s\t %-20s\t %-5s\t %-12d \t%-30s\n", pc->data[ret].name,
			pc->data[ret].sex,
			pc->data[ret].tele,
			pc->data[ret].age,
			pc->data[ret].addr);
	}
}
//修改指定联系人
void ModifyContact(struct Contact* pc)
{
	printf("请输入修改人的信息:>");
	char name[NAME];
	scanf("%s", name);
	int ret = Findname(pc, name);
	if (ret == -1)
	{
		printf("要查找的人不存在\n");
	}
	else
	{
		//修改
		//就相当于重新录入信息
		printf("请输入名字:>");
		scanf("%s", pc->data[ret].name);
		printf("请输入性别:>");
		scanf("%s", pc->data[ret].sex);
		printf("请输入电话:>");
		scanf("%s", pc->data[ret].tele);
		printf("请输入年龄:>");
		scanf("%d", &(pc->data[ret].age));
		printf("请输入地址:>");
		scanf("%s", pc->data[ret].addr);
		printf("修改成功\n");
	}
}
//比较
int CmpByAge(const void* e1, const void* e2)
{
	return ((struct PeoInfo*)e1)->age - ((struct PeoInfo*)e2)->age;
}
//按照年龄来排序
void SortContact(struct Contact* pc)
{
	//用qsort排序
	qsort(pc->data, pc->sz, sizeof(struct PeoInfo), CmpByAge);
}
void DistoryContact(struct Contact* pc) 
{
	free(pc->data);
	pc->data = NULL;
	pc->capacity = 0;
	pc->sz = 0;
}

//保存通讯录
void SaveContact(struct Contact* pc)
{
	//打开文件,用二进制的方式写
	FILE* tt = fopen("Contact.txt", "wb");
	//判断是否为空指针
	if (tt == NULL)
	{
		perror("SaveContact:fopen");
		return;
	}
	//可以写了
	for (int i = 0; i < pc->sz; i++)
	{
		fwrite(pc->data + i, sizeof(struct PeoInfo), 1, tt);
	}

	//关闭文件
	fclose(tt);
	tt = NULL;
	return 0;
}

🐖总结

⭐我们现在就将三种形式的通讯录写完了,相信大家肯定或多多少都有点收获,如果大家不太理解,可以私信我,看到必会,如果对大家有点帮助,希望大家一键三联,这将是我的动力。欢迎大家食用。😊😊

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1572.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

C++ Reference: Standard C++ Library reference: C Library: cstring: strncat

C官网参考链接&#xff1a;https://cplusplus.com/reference/cstring/strncat/ 函数 <cstring> strncat char * strncat ( char * destination, const char * source, size_t num ); 从字符串中追加字符 将source的第一个num个字符追加到destination&#xff0c;并追加…

重型机床热误差补偿温度敏感测点的识别与优化选择

重型机床热误差补偿温度敏感测点的识别与优化选择 动机与主要贡献 ● 热误差预测的性能主要取决于预测模型的准确性和鲁棒性以及输入的温度变量 ● 在大型数控机床热误差补偿方案中&#xff0c;由于温度敏感点的结构和发热机理复杂&#xff0c;目前仍缺乏有效的温度敏感点识别…

java---贪心---区间分组(每日一道算法2022.10.28)

题目&#xff1a; 给定 N 个闭区间 [ai,bi]&#xff0c;请你将这些区间分成若干组&#xff0c;使得每组内部的区间两两之间&#xff08;包括端点&#xff09;没有交集&#xff0c;并使得组数尽可能小 输出最小组数 第一行包含整数 N&#xff0c;表示区间数 接下来 N 行&#x…

Redis篇(2)——main函数

众所周知&#xff0c;redis是C语言写的。那么main函数来一波 int main(int argc, char **argv) {struct timeval tv;int j;//运行测试方法 #ifdef REDIS_TESTif (argc 3 && !strcasecmp(argv[1], "test")) {if (!strcasecmp(argv[2], "ziplist")…

SpringBoot

SpringBoot项目搭建方式1项目搭建方式2SpringBoot文件配置application.propertiesapplication.ymlSpringBoot整合MybatisSpringBoot整合logbackSpringBoot整合pageHelperSpringBoot整合DruidSpringBoot整合FreeMarkerFreeMarker常用指令(遍历List集合)FreeMarker遍历Map集合Spr…

【树莓派不吃灰】Linux系统下必知必会的一些命令

目录1. 前言2. 必知必会命令2.1 ls -al 列出当前目录下的文件2.2 cd 改变目录2.3 pwd 输出当前目录2.4 clear 清屏命令2.5 mkdir 新建目录2.6 rmdir 删除目录2.7 cat 显示或连接文件内容2.8 touch 创建文件 & cat > 创建文件2.9 rm 删除文件2.10 mv 移动/重命名文件/目录…

【小程序开发】事件监听 | 类型划分 | 属性分析

&#x1f373;作者&#xff1a;贤蛋大眼萌&#xff0c;一名很普通但不想普通的程序媛\color{#FF0000}{贤蛋 大眼萌 &#xff0c;一名很普通但不想普通的程序媛}贤蛋大眼萌&#xff0c;一名很普通但不想普通的程序媛&#x1f933; &#x1f64a;语录&#xff1a;多一些不为什么的…

基于SSM实现前后端分离在线考试管理系统

作者主页&#xff1a;编程指南针 作者简介&#xff1a;Java领域优质创作者、CSDN博客专家 、掘金特邀作者、多年架构师设计经验、腾讯课堂常驻讲师 主要内容&#xff1a;Java项目、毕业设计、简历模板、学习资料、面试题库、技术互助 文末获取源码 项目编号&#xff1a;BS-XX-…

[kafka]二.优化(如何保证不丢数据,且不重复[一次且仅一次])

二.优化 1.不丢失数据ack-1 当Producer向Leader发送消息时&#xff0c;可以通过ack的值来设置可靠性级别。 1&#xff09;1&#xff08;默认&#xff09; 意味着ISR中的Leader已成功收到消息并且Producer得到Leader收到消息的确认。如果ISR中的副本数还没有来得及拉取数据就…

Linux 进程替换深剖

目录传统艺能&#x1f60e;概念&#x1f914;细则&#x1f914;原理&#x1f914;exec 函数&#x1f914;execl&#x1f60b;execlp&#x1f60b;execle&#x1f60b;execv&#x1f60b;execvp&#x1f60b;execve&#x1f60b;实现简易 shell&#x1f914;传统艺能&#x1f60…

【python】之常用类型(包括进制)之间的转换

个人主页&#xff1a;天寒雨落的博客_CSDN博客-C,CSDN竞赛,python领域博主 特别标注&#xff1a;仅为自己的学习记录笔记&#xff0c;方便复习和加深记忆&#xff0c;仅供借鉴参考&#xff01; 目录 一、字符和整数之间的转换 1.整数转字符 chr(x) 2.字符转整数 ord(x) 二、…

Git操作复习笔记

Git操作复习笔记一、git基础1.1 安装1.2 简单的命令1.2.1 基本工作流程1.2.3 git使用前配置1.2.4 git提交步骤1.2.5 恢复记录1.2.6 撤销二、git分支操作2.1 分支细分2.2 分支命令2.3 暂时保存更改三、github操作3.1 多人协作开发的流程3.2 创建远程仓库3.3 远程仓库克隆到本地仓…

【K8S系列】Kubernetes的网络模型

目录 一、k8s的三种网络 二、service网络 2.1 netfilter 2.2 iptables 2.3 clustip 一、k8s的三种网络 Node Network: 与外部网络接口 Service Network&#xff1a; ipvs规则当中的网络、路由提供调度 Pod Network&#xff1a; 节点当中pod的内部网络无法与外界通信 其中&…

【python初学者日记】selenium初体验——“秒杀商品”、“清空购物车”技能养成记(一)

【python初学者日记】selenium初体验——“秒杀商品”、“清空购物车”技能养成记&#xff08;一&#xff09;用python解决“清空购物车”、“秒杀商品”问题合集&#xff1a;1、Mac版在pycharm和终端上使用pip显示&#xff1a;pip: command not found Mac2、Mac版在pycharm中*…

毛球修剪器方案开发的工作原理和构成

本文介绍了毛球修剪器方案开发的工作原理&#xff1b;不管是羊毛衫、兔子衫还是普通纤维衫&#xff0c;时间一长都不可避免地会有很多毛球。它看起来脏又乱&#xff0c;穿起来特别不雅观。用除毛器剃毛球可以轻松去除毛衣的原始绒毛&#xff0c;而毛衣将失去其原有的保暖性。 原…

HTML登录页面

第一步:构建HTML框架 简介&#xff1a;本文用最通俗的语言&#xff0c;一步步教会大家CSS构建登录页面。 首先构建HTML框架&#xff0c;包含用户名&#xff0c;密码&#xff0c;记住密码&#xff0c;注册这几个功能。 如果大家HTML不牢固&#xff0c;请看我的这篇博客:https:/…

【数据结构】线性表之顺序表详解

&#x1f9d1;‍&#x1f4bb;作者&#xff1a; 情话0.0 &#x1f4dd;专栏&#xff1a;《数据结构》 &#x1f466;个人简介&#xff1a;一名双非研究生的编程菜鸟&#xff0c;在这里分享自己的编程学习笔记&#xff0c;欢迎大家的指正与点赞&#xff0c;谢谢&#xff01; 顺…

32、Java——迷你图书管理器(对象+JDBC)

✅作者简介&#xff1a;热爱国学的Java后端开发者&#xff0c;修心和技术同步精进。 &#x1f34e;个人主页&#xff1a;乐趣国学的博客 &#x1f34a;个人信条&#xff1a;不迁怒&#xff0c;不贰过。小知识&#xff0c;大智慧。 &#x1f49e;当前专栏&#xff1a;Java案例分…

SpringBoot交友APP项目实战(详细介绍+案例源码) - 10.网关配置

系列文章目录 1. 项目介绍及环境配置 2. 短信验证码登录 3. 用户信息 4. MongoDB 5. 推荐好友列表/MongoDB集群/动态发布与查看 6. 圈子动态/圈子互动 7. 即时通讯&#xff08;基于第三方API&#xff09; 8. 附近的人(百度地图APi) 9. 小视频 10.网关配置 文章目录系列文章目录…

【数据结构练习题——查找】

题目&#xff1a;给定如下关键字序列 &#xff08;36,23,51,6&#xff0c;58,48,39,8&#xff0c;88,76,63,17&#xff09; &#xff08;1&#xff09;按表中顺序建立一棵初始为空的二叉排序树&#xff0c;画出该二叉排序树。 &#xff08;2&#xff09;求上述二叉排序树中等…