【C语言】通讯录系统实现 (保姆级教程,附源码)

这篇具有很好参考价值的文章主要介绍了【C语言】通讯录系统实现 (保姆级教程,附源码)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

目录

1、通讯录系统介绍

2、代码分装

3、代码实现步骤

3.1、制作菜单menu函数以及游戏运行逻辑流程

3.2、封装人的信息PeoInfo以及通讯录Contact结构体类型

3.3、初始化通讯录InitContact函数

3.4、增加联系人AddContact函数

3.5、显示所有联系人ShowContact函数

3.6、删除联系人DelContact函数以及判断是否存在FindByName函数

3.7、查找指定联系人SearchContact函数

3.8、修改指定联系人ModifyContact函数

3.9、以年龄排序联系人SortContact函数

4、使用动态规划优化通讯录 

5、通讯录系统完整代码


【C语言】通讯录系统实现 (保姆级教程,附源码),c语言,开发语言,算法,c++,visualstudio

1、通讯录系统介绍

实现一个通讯录:

  1. 可以保存100个人的信息(后续优化成动态开辟)
  2. 增加人的信息
  3. 删除指定联系人的信息
  4. 查询指定联系人的信息 
  5. 修改指定联系人的信息
  6. 排序通讯录的信息
  7. 显示所有联系人的信息

其中,人的信息包括:名字、年龄、性别、电话 、地址

2、代码分装

源文件:

test.c: 测试通讯录的基本功能

game.c: 实现通讯录的相关函数

头文件:

game.h: 相关函数和类型的声明,整个代码要引用的头文件以及宏定义

【C语言】通讯录系统实现 (保姆级教程,附源码),c语言,开发语言,算法,c++,visualstudio

3、代码实现步骤

3.1、制作菜单menu函数以及游戏运行逻辑流程

  • 首先在 test.c 中定义一个menu函数打印菜单,提示玩家进行选择。
  • scanf接收玩家输入并用switch判断,针对判断进行相应操作,输入错误时提示选择错误,重新选择。而为了能够让用户重新选择以及完成一个功能操作时再继续下一个功能操作,需要使用do while语句将它们包含起来。

使用枚举一一列举菜单选择的可能取值,便于后续使用时能够见名知意,增加代码可读性。 

【test.c】 

void menu()
{
	printf("***********************************\n");
	printf("******  1.add      2.del     ******\n");
	printf("******  3.search   4.modify  ******\n");
	printf("******  5.show     6.sort    ******\n");
	printf("******  0.exit               ******\n");
	printf("***********************************\n");
}

enum Option  //枚举常量
{
	EXIT,
	ADD,
	DEL,
	SEARCH,
	MODIFY,
	SHOW,
	SORT
};

int main()
{
	int input = 0;
	do
	{
		menu();
		printf("请输入你的选择:>");
		scanf("%d", &input);
		switch (input)
		{
		case ADD:
			break;
		case DEL:
			break;
		case SEARCH:
			break;
		case MODIFY:
			break;
		case SHOW:
			break;
		case SORT:
			break;
		case EXIT:
			printf("退出通讯录\n");
			break;
		default:
			printf("选择错误,重新选择\n");
			break;
		}
	} while (input);
	return 0;
}

3.2、封装人的信息PeoInfo以及通讯录Contact结构体类型

创建结构体类型PeoInfo用于描述人的信息,然后再创建一个Contact结构体包含PeoInfo和个数,这样一个通讯录结构体类型便完成了 。

为了方便后续代码的修改,这里将所有常量都用 #define 定义了变量。

【contact.h】

#define NAME_MAX 20
#define SEX_MAX 5
#define TELE_MAX 12
#define ADDR_MAX 30

#define MAX 100


typedef struct PeoInfo
{
	char name[NAME_MAX];
	int age;
	char sex[SEX_MAX];
	char tele[TELE_MAX];
	char addr[ADDR_MAX];
}PeoInfo;

typedef struct Contact
{
	PeoInfo data[MAX];
	int sz; //记录的是当前通讯录中存放的人的信息个数
}Contact;

3.3、初始化通讯录InitContact函数

【contact.h】

//初始化通讯录
void InitContact(Contact* pc);

【contact.c】 

assert断言,对传入的指针进行判断,防止对空指针进行操作。

使用 memset函数 初始化结构体中的数据。针对memset函数,如果不了解其原理,可以前往往期博客进行学习了解:

一篇博客学会系列(1) —— C语言中所有字符串函数以及内存函数的使用和注意事项_Hacynn的博客-CSDN博客https://blog.csdn.net/zzzzzhxxx/article/details/133243791?spm=1001.2014.3001.5501

void InitContact(Contact* pc)
{
	assert(pc);
	pc->sz = 0;
	memset(pc->data, 0, sizeof(pc->data));
}

【test.c】 

int main()
{
	int input = 0;
    Contact con; //通讯录
	InitContact(&con);//初始化通讯录
	do
	{
		menu();
		printf("请输入你的选择:>");
		scanf("%d", &input);
		switch (input)
		{
		case ADD:
			break;
		case DEL:
			break;
		case SEARCH:
			break;
		case MODIFY:
			break;
		case SHOW:
			break;
		case SORT:
			break;
		case EXIT:
			printf("退出通讯录\n");
			break;
		default:
			printf("选择错误,重新选择\n");
			break;
		}
	} while (input);
	return 0;
}

3.4、增加联系人AddContact函数

【contact.h】

//增加联系人
void AddContact(Contact* pc);

【contact.c】

assert断言,对传入的指针进行判断,防止对空指针进行操作。 

需要判断当sz不等于MAX时再继续进行添加操作,防止溢出。

此处需要注意的是,人的信息中只有age是整型,其他的name、sex、tele、addr都为字符数组,scanf在接收age的时候需要取出age的地址,即 &(pc->data[pc->sz].age)。

void AddContact(Contact* pc)
{
	assert(pc);
	if (pc->sz == MAX)
	{
		printf("通讯录已满,无法增加\n");
		return;
	}
	
    //增加信息
	printf("请输入名字:");
	scanf("%s", pc->data[pc->sz].name);
	printf("请输入年龄:");
	scanf("%d", &(pc->data[pc->sz].age));
	printf("请输入性别:");
	scanf("%s", pc->data[pc->sz].sex);
	printf("请输入电话:");
	scanf("%s", pc->data[pc->sz].tele);
	printf("请输入地址:");
	scanf("%s", pc->data[pc->sz].addr);

	pc->sz++;
	printf("增加成功\n");

}

为了查看增加功能是否正确,我们需要显示通讯录信息,因此接下来我们实现一个函数 ShowContact 用于显示所有联系人的信息。

3.5、显示所有联系人ShowContact函数

【contact.h】

虽然显示操作不需要修改通讯录中的内容,但是出于效率和空间的考虑,还是选择传址,然后使用const修饰。

//显示所有联系人
void ShowContact(const Contact* pc);

【contact.c】

注意11行和14行的不同。

因为11行打印的标题行都是字符串,所以都是用了%s,而14行的信息行中年龄是整型的 ,因此需要使用%d打印,需要注意这里的不同。

void ShowContact(const Contact* pc)
{
	assert(pc);
	if (pc->sz == 0)
	{
		printf("通讯录为空,无需打印\n");
		return;
	}
	int i = 0;

	printf("%-20s%-5s%-5s%-12s%-30s\n", "名字", "年龄", "性别", "电话", "地址");  //标题行
	for ( i = 0; i < pc->sz; i++)
	{
		printf("%-20s%-5d%-5s%-12s%-30s\n",
			pc->data[i].name, pc->data[i].age, pc->data[i].sex, pc->data[i].tele, pc->data[i].addr);
	}
}

【test.c】

void menu()
{
	printf("***********************************\n");
	printf("******  1.add      2.del     ******\n");
	printf("******  3.search   4.modify  ******\n");
	printf("******  5.show     6.sort    ******\n");
	printf("******  0.exit               ******\n");
	printf("***********************************\n");
}

enum Option
{
	EXIT,
	ADD,
	DEL,
	SEARCH,
	MODIFY,
	SHOW,
	SORT
};

int main()
{
	int input = 0;
	Contact con; //通讯录
	InitContact(&con);//初始化通讯录
	do
	{
		menu();
		printf("请输入你的选择:>");
		scanf("%d", &input);
		switch (input)
		{
		case ADD:
			AddContact(&con);
			break;
		case DEL:
			break;
		case SEARCH:
			break;
		case MODIFY:
			break;
		case SHOW:
			ShowContact(&con);
			break;
		case SORT:
			break;
		case EXIT:
			printf("退出通讯录\n");
			break;
		default:
			printf("选择错误,重新选择\n");
			break;
		}
	} while (input);
	return 0;
}

 下面试着添加联系人并打印通讯录:

 【C语言】通讯录系统实现 (保姆级教程,附源码),c语言,开发语言,算法,c++,visualstudio

3.6、删除联系人DelContact函数以及判断是否存在FindByName函数

【contact.h】

//删除联系人
void DelContact(Contact* pc);

【contact.c】

  • 因为通过名字判断此人是否存在的FindByName函数这个功能在其他操作上也需要使用到,所以最好将它封装成一个函数,减少代码冗余并且提高写代码效率。
  • 当FindByName函数在通讯录中找到此人时返回此人在data数组中的下标,找不到是返回-1。
  • 又因为FindByName函数只在contact.c中被使用,因此可以加上static关键字修饰。
static int FindByName(Contact* pc, char name[])
{
	assert(pc);
	int i = 0;
	for ( i = 0; i < pc->sz; i++)
	{
		if (strcmp(pc->data[i].name, name) == 0)  //两个字符串比较用strcmp
			return i;
	}
	return -1;
}

void DelContact(Contact* pc)
{
	char name[NAME_MAX];
	assert(pc);
	if (pc->sz == 0)
	{
		printf("通讯录为空,无法删除\n");
		return;
	}
	printf("请输入要删除人的名字:");
	scanf("%s", name);
	//查找名字为name的人
	int ret = FindByName(pc, name);
	if (ret == -1)
	{
		printf("要删除的人不存在\n");
		return;
	}
	//删除这个人
	int i = 0;
	for (i = ret; i < pc->sz - 1; i++)    //注意此处的sz - 1 
	{
		pc->data[i] = pc->data[i + 1];
	}

	pc->sz--;
	printf("删除成功\n");
}

【删除操作图解】 

这里以0~6的下标作为例子,假如ret返回的下标时1。

只需要将ret后面的所有内容向前平移一位,就可以覆盖掉要ret指向的内容,然后再对sz--,这样变相地完成了对信息的删除。等将来又有新联系人加入时,因为sz--了所以写入信息时会覆盖掉下标为6中的内容。

【C语言】通讯录系统实现 (保姆级教程,附源码),c语言,开发语言,算法,c++,visualstudio

此时使用该函数尝试删除一下联系人,结果是可以的。

【C语言】通讯录系统实现 (保姆级教程,附源码),c语言,开发语言,算法,c++,visualstudio

3.7、查找指定联系人SearchContact函数

【contact.h】

//查找指定联系人
void SearchContact(Contact* pc);

【contact.c】

依然是调用FindByName函数进行判断,有此人则返回下标,没有此人则返回-1。

找到之后直接打印就行。

void SearchContact(Contact* pc)
{
	char name[NAME_MAX];
	assert(pc);
	printf("请输入要查找人的名字:");
	scanf("%s", name);

	int ret = FindByName(pc, name);
	if (ret == -1)
	{
		printf("要查找的人不存在\n");
		return;
	}
	//显示查查找到的信息

	printf("%-20s%-5s%-5s%-12s%-30s\n", "名字", "年龄", "性别", "电话", "地址");
	printf("%-20s%-5d%-5s%-12s%-30s\n",
		pc->data[ret].name, pc->data[ret].age, pc->data[ret].sex, pc->data[ret].tele, pc->data[ret].addr);


}

3.8、修改指定联系人ModifyContact函数

【contact.h】

//修改指定联系人
void ModifyContact(Contact* pc);

【contact.c】

依然是调用FindByName函数进行判断,有此人则返回下标,没有此人则返回-1。

找到之后直接将该下标下的所有信息都重新接收并覆盖,就完成了修改操作。

void ModifyContact(Contact* pc)
{
	char name[NAME_MAX];
	assert(pc);
	printf("请输入要修改人的名字:");
	scanf("%s", name);

	int ret = FindByName(pc, name);
	if (ret == -1)
	{
		printf("要修改的人不存在\n");
		return;
	}
	//修改
	printf("请输入名字:");
	scanf("%s", pc->data[ret].name);
	printf("请输入年龄:");
	scanf("%d", &(pc->data[ret].age));
	printf("请输入性别:");
	scanf("%s", pc->data[ret].sex);
	printf("请输入电话:");
	scanf("%s", pc->data[ret].tele);
	printf("请输入地址:");
	scanf("%s", pc->data[ret].addr);
}

3.9、以年龄排序联系人SortContact函数

【contact.h】

//排序联系人
void SortContact(Contact* pc);

【contact.c】

qsort可以对任意数据进行排序,因此使用qsort以年龄为关键字进行排序。

关于 qsort函数 我在往期的博客中有进行详细讲解,这里由于篇幅原因,就不过多赘述,如果不懂或者想要更深入了解的话,可以前往:【C语言】指针的进阶(二)—— 回调函数的讲解以及qsort函数的使用方式_Hacynn的博客-CSDN博客https://blog.csdn.net/zzzzzhxxx/article/details/132941465?spm=1001.2014.3001.5501

int cmp_age(const void* e1, const void* e2)
{
	return ((PeoInfo*)e1)->age - ((PeoInfo*)e2)->age;
}

void SortContact(Contact* pc)
{
	assert(pc);
	if (pc->sz == 0)
	{
		printf("通讯录为空,无需排序\n");
		return;
	}
	qsort(pc, pc->sz, sizeof(PeoInfo), cmp_age);
	printf("排序成功\n");
}

到这里通讯录的实现就基本完成了,但是有些读者可以注意到,这个通讯录还存在一些问题:

  1. 录入的信息,等程序结束后就不存在了,这是因为数据存放在内存中的。为了解决这个问题,需要使用到文件存储的知识。
  2. 通讯录的大小是固定的100个元素,只能最多存放100个人。当信息太少时,就会导致空间剩余过大浪费空间,而当信息太多时空间又太小了无法进行存入,而解决这个问题需要使用到动态内存管理的知识。下面就来优化一下通讯录。

4、使用动态规划优化通讯录 

规定:

  1. 通讯录刚开始时可以存放3个人的信息。#define DEFAULT_SZ 3
  2. 当空间放满时,自动增加容量,每次增加2个信息的空间。#define DEFAULT_INC 2

定义通讯录Contact结构体:

因为数组空间是固定的,因此这里改成了指针,后续初始化时对data指针进行calloc动态开辟空间,并且增加用于记录当前最大容量的变量capacity

静态版本
//typedef struct Contact
//{
//	PeoInfo data[MAX];
//	int sz; //记录的是当前通讯录中存放的人的信息个数
//}Contact;

//动态版本
typedef struct Contact
{
	PeoInfo* data;
	int sz; //记录的是当前通讯录中存放的人的信息个数
    int capacity; //记录的时通讯录当前的最大容量
}Contact;

初始化通讯录InitContact函数: 

此时就可以使用calloc对data指针进行动态开辟空间,如果开辟失败则用perror打印错误信息。

对于perror函数的使用以及注意事项,在往期博客中有进行详细讲解,这就不过多赘述,感兴趣的可以前往:一篇博客学会系列(1) —— C语言中所有字符串函数以及内存函数的使用和注意事项_Hacynn的博客-CSDN博客https://blog.csdn.net/zzzzzhxxx/article/details/133243791?spm=1001.2014.3001.5501

静态版本
//void InitContact(Contact* pc)
//{
//	assert(pc);
//	pc->sz = 0;
//	memset(pc->data, 0, sizeof(pc->data));
//}

//动态版本
void InitContact(Contact* pc)
{
	assert(pc);
	pc->sz = 0;
	pc->capacity = DEFAULT_SZ;  //#define DEFAULT_SZ 3
	pc->data = (PeoInfo*)calloc(pc->capacity, sizeof(PeoInfo));
	if (pc->data == NULL)
	{
		perror("InitContact->calloc");
		return;
	}
}

 增加联系人AddContact函数:

因为此时使用了动态规划,所以不会存在通讯录满了无法增加的情况,此时if语句改为判断是否已满,如果已满则使用realloc增容。此时需要用另一个指针ptr接收realloc的空间,判断ptr指向的空间是否开辟成功,成功时再将ptr赋值给pc->data,防止数据丢失。

静态版本
//void AddContact(Contact* pc)
//{
//	assert(pc);
//	if (pc->sz == MAX)
//	{
//		printf("通讯录已满,无法增加\n");
//		return;
//	}
//	
//	printf("请输入名字:");
//	scanf("%s", pc->data[pc->sz].name);
//	printf("请输入年龄:");
//	scanf("%d", &(pc->data[pc->sz].age));
//	printf("请输入性别:");
//	scanf("%s", pc->data[pc->sz].sex);
//	printf("请输入电话:");
//	scanf("%s", pc->data[pc->sz].tele);
//	printf("请输入地址:");
//	scanf("%s", pc->data[pc->sz].addr);
//
//	pc->sz++;
//	printf("增加成功\n");
//
//}

//动态版本
void AddContact(Contact* pc)
{
	assert(pc);
	if (pc->sz == pc->capacity)
	{
		PeoInfo* ptr = (PeoInfo*)realloc(pc->data, (pc->capacity + DEFAULT_INC) * sizeof(PeoInfo));
		if (ptr != NULL)
		{
			pc->data = ptr;
			pc->capacity += DEFAULT_INC;  //#define DEFAULT_INC 2
            printf("增容成功\n");
		}
		else
		{
			perror("AddContact->realloc");
			return;
		}
	}

	printf("请输入名字:");
	scanf("%s", pc->data[pc->sz].name);
	printf("请输入年龄:");
	scanf("%d", &(pc->data[pc->sz].age));
	printf("请输入性别:");
	scanf("%s", pc->data[pc->sz].sex);
	printf("请输入电话:");
	scanf("%s", pc->data[pc->sz].tele);
	printf("请输入地址:");
	scanf("%s", pc->data[pc->sz].addr);

	pc->sz++;
	printf("增加成功\n");

}

在EXIT退出通讯录时候记得对动态开辟的空间进行free操作:

定义一个DestroyContact函数用于free掉动态开辟的空间。

【contact.h】

//销毁通讯录
void DestroyContact(Contact* pc);

【contact.c】

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

5、通讯录系统完整代码

 源码已经上传至gitee中,有需要可以前往领取:Contact/Contact · Nadez/Study_c - 码云 - 开源中国 (gitee.com)

【C语言】通讯录系统实现 (保姆级教程,附源码),c语言,开发语言,算法,c++,visualstudio

 【C语言】通讯录系统实现 (保姆级教程,附源码),c语言,开发语言,算法,c++,visualstudio

如果觉得作者写的不错,求给博主一个大大的点赞支持一下,你们的支持是我更新的最大动力!文章来源地址https://www.toymoban.com/news/detail-719083.html

如果觉得作者写的不错,求给博主一个大大的点赞支持一下,你们的支持是我更新的最大动力!

如果觉得作者写的不错,求给博主一个大大的点赞支持一下,你们的支持是我更新的最大动力!

到了这里,关于【C语言】通讯录系统实现 (保姆级教程,附源码)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【C语言】实现通讯录管理系统

    大家好,我是苏貝,本篇博客带大家实现通讯录,如果你觉得我写的还不错的话,可以给我一个赞👍吗,感谢❤️ 本文将使用C语言来实现通讯录管理系统,该通讯录包括若干联系人,和每个联系人的姓名、年龄、性别、电话、地址。此通讯录的功能包括:增加联系人信息,

    2024年02月08日
    浏览(49)
  • Python 基于列表实现的通讯录管理系统(有完整源码)

    目录 通讯录管理系统 PersonInformation类 ContactList类 menu函数 main函数 程序的运行流程 完整代码 运行示例 这是一个基于文本的界面程序,用户可以通过命令行与之交互,它使用了CSV文件来存储和读取联系人信息,这使得数据可以持久化保存。此外,程序还提供了一些基本的输入

    2024年04月15日
    浏览(48)
  • C语言用链表实现通讯录管理系统

    目录 总体思路 具体代码 编译通过 总体代码 一、创建一个结构体保存通讯录信息。 二、构建链表,并存于文件中。 三、实现链表结点的增加、删除、查询、输出。 一、创建一个结构体,保存信息。 二、用尾插法创建一个链表,并让用户选择是否输入数据。 三、将链表数据

    2024年02月02日
    浏览(52)
  • 使用C语言实现通讯录管理系统1.0版本(持续更新)

    本篇文章会教大家用C语言实现一个通讯录系统,此程序将会持续更新优化。觉得博主写的不错的朋友可以关注点赞收藏一波,支持一下博主,感谢大家! 此通讯录系统可以存储1000个联系人的:姓名,性别,年龄,电话号码,家庭地址。 主要实现的系统功能有:添加联系人,

    2024年02月03日
    浏览(56)
  • 数据结构课设—C语言实现通讯录管理系统(顺序表实现)

    这个项目是我大一时期数据结构的课程设计,在我潜心研究下出来的,对于当时的我来说算是非常满意啦,哈哈哈哈哈哈哈哈哈哈☆*: .。. o(≧▽≦)o .。.:*☆ 目录 一、引言 1.目的: 2.意义: 3.主要任务: 4.程序功能: 5.编译工具: 二、正文 1.系统模块: 2.算法流程图: 3.各

    2024年02月02日
    浏览(78)
  • 文件操作介绍及C语言实现通讯录管理系统3.0最终版(文件操作版本)

    上一篇文章我们学习了动态内存开辟的相关知识点,并用动态内存函数优化了我们的通讯录,但通讯录还有需要改进的地方,比如,正常情况下的通讯录,应该可以一直保存联系人信息,而不是退出就清空了,这就需要我们实实在在的保存下来一个通讯录。 接下来我会给大家

    2023年04月08日
    浏览(58)
  • 动态内存管理函数介绍及C语言实现通讯录管理系统2.0版(动态增长版本)

    之前向大家介绍了C语言实现通讯录管理系统1.0版本,但该版本有明显的不足之处,比如:一开始就开辟了1000个date数组,如果联系人很少,那么就会造成严重的内存浪费,或者联系人超过了1000人,那么原数组就放不下了,所以今天我们考虑使用动态内存管理的办法来实现一个

    2023年04月08日
    浏览(49)
  • 通讯录实现【C语言】

    目录 前言 一、整体逻辑分析 二、实现步骤 1、创建菜单和多次操作问题 2、创建通讯录 3、初始化通讯录 4、添加联系人 5、显示联系人 6、删除指定联系人 ​7、查找指定联系人 8、修改联系人信息 9、排序联系人信息 三、全部源码 我们上期已经详细的介绍了自定义类型,本

    2024年02月11日
    浏览(59)
  • C语言---认识动态内存管理并实现一个动态通讯录:静态通讯录别来沾边

    👧个人主页:@小沈熬夜秃头中୧⍤⃝❅ 😚小编介绍:欢迎来到我的乱七八糟小星球🌝 📋专栏:C语言学习 🔑本章内容:动态内存管理 送给各位💌:当你的能力还驾驭不了你的目标时那你就应该沉下心来历练 记得 评论📝 +点赞👍 +收藏😽 +关注💞哦~ 提示:以下是本篇

    2024年02月08日
    浏览(92)
  • 【C语言】优化通讯录管理系统

    大家好,我是苏貝,本篇博客带大家优化上一篇的通讯录,如果你觉得我写的还不错的话,可以给我一个赞👍吗,感谢❤️ 在上一篇博文 实现通讯录管理系统 的最后,我们了解了那段代码的问题:通讯录的大小是固定的100个元素,如果想要存放1000个人的信息,那么空间就

    2024年02月06日
    浏览(47)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包