C语言实现通讯录(静态、动态增容、文件储存)

目录

一、前言

二、通讯录的实现

1.大体框架

(1)菜单的实现

(2)联系人结构体的创建

(3)菜单选项功能

2.通讯录的功能实现

(1)添加通讯录联系人

(2)删除指定联系人

(3)查找指定联系人

(4)修改指定联系人

(5)显示通讯录的信息

(6)清空所有联系人

(7)以名字排序所有联系人

三.通讯录的优化

1.动态增容

(1)初始化通讯录

(2)增加联系人

(3)清空所有联系人

2.写入文件

(1)初始化时,读取文件信息

(2)退出时,将信息保存到文件中


一、前言

模拟实现通讯录系统,涉及多种循环,枚举,指针,结构体等,很好的将我们的知识串联起来,是一次有意义的练习实践。

本文将用C语言模拟实现一个通讯录系统,其功能包括添加联系人,删除指定联系人,查找指定联系人,修改指定联系人等功能,可以根据需要再自行添加功能。

(源代码附在末尾)


二、通讯录的实现

1.大体框架

(1)菜单的实现

用多个printf打印一个简单的菜单界面 


(2)联系人结构体的创建

 将我们会使用到的一些变量进行声明,例如最大联系人个数、地址长度。


 创建一个名为PeoInfo的结构体,成员有name,age,sex,addr,tele,即联系人的姓名,年龄,性别,地址,电话号码,来表示一个联系人的信息。

 再创建一个Contact结构体,来保存PeoInfo结构体写入的联系人信息和联系人个数。


 


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

 初始化数组,结构体置为0,大小置为0。

 

(3)菜单选项功能

用枚举,给上述符号赋值,可以与菜单对应,并且直观明了。

	do
	{
		menu();
		printf("请选择>");
		scanf("%d", &input);
		switch (input)
		{
		case ADD:
			AddContact(&con);
			break;
		case DEL:
			DelContact(&con);
			break;
		case SEACHER:
			SearchContact(&con);
			break;
		case MODIFY:
			ModifyContact(&con);
			break;
		case SHOW:
			ShowContact(&con);
			break;
		case EMPTY:
			EmptyContact(&con);
			break;
		case SORT:
			SortContact(&con);
			break;
		case EXIT:
			DestroyContact(&con);
			printf("退出通讯录\n");
			break;
		default:
			printf("选择错误,请重新选择\n");
			break;
		} while (input);

 使用do while语句和switch语句,实现选择菜单中的不同功能。


 

2.通讯录的功能实现

(1)添加通讯录联系人

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].addr);
	printf("请输入电话:>");
	scanf("%s", pc->data[pc->sz].tele);
	pc->sz++;
}

先判断通讯录是否未满 ,如果满了,提示并退出                                                                              如果没满,则直接使用scanf来填写联系人的信息


(2)删除指定联系人

void DelContact(Contact* pc)
{
	assert(pc);
	char name[NAME_MAX] = { 0 };
	if (pc->sz == 0)
	{
		printf("通讯录为空,无法删除\n");
		return;
	}
	printf("请输入你想删除的联系人的姓名:>");
	scanf("%s", name);
	int ret = FindContact(pc, name);
	if (-1 == ret)
	{
		printf("通讯录中没有此人\n");
		return;
	}
	int i = 0;
	for (i = ret; i < pc->sz - 1; i++)
	{
		pc->data[i] = pc->data[i + 1];
	}
	pc->sz--;
	printf("删除成功\n");
}

 首先判断通讯录是否为空,为空返回,不为空则继续进行。                                                              输入想要删除的人的姓名,然后通过FindContact函数去在通讯录中查找,若没找到,返回-1,若找到了,返回要删除人在结构体数组的序号,用ret接收。再判断ret的值,为-1报错,否则继续下面代码。

定义一个变量i,等于要删除人在结构体数组的序号,将后面一位的信息替换到这个人,通过循环实现将指定人后的每一位成员信息提前一位,最后再将sz(联系人个数)减一。

FindContact函数

int FindContact(const Contact* pc, char name[])
{
	int i = 0;
	for (i = 0; i < pc->sz; i++)
	{
		if (strcmp(pc->data[i].name, name) == 0)
		{
			return i;
		}
	}
	return -1;
}

 使用for对结构体数组进行遍历,用strcmp函数判断pc->data[i].name(结构体数组中元素的名字)和 name(要查询的名字)是否相等,相等返回0,在if中成立,则函数返回指定人在结构体数组的序号。若遍历完也没有找到,函数则返回-1。

strcmp函数 两个字符串自左向右逐个字符相比(按 ASCII 值大小相比较),直到出现不同的字符或遇 \0 为止。


(3)查找指定联系人

void SearchContact(const Contact* pc)
{
	assert(pc);
	char name[NAME_MAX] = { 0 };
	if (pc->sz == 0)
	{
		printf("通讯录为空,无法查找\n");
		return;
	}
	printf("请输入你想查找的联系人的姓名:>");
	scanf("%s", name);
	int pos = FindContact(pc, name);
	if (-1 == pos)
	{
		printf("通讯录中没有此人\n");
		return;
	}
	printf("%-20s\t%-4s\t%-5s\t%-20s\t%-12s\n", "名字", "年龄", "性别", "地址", "电话");
	printf("%-20s\t%-4d\t%-5s\t%-20s\t%-12s\n",
		pc->data[pos].name,
		pc->data[pos].age,
		pc->data[pos].sex,
		pc->data[pos].addr,
		pc->data[pos].tele);
}

 同删除指定联系人一样的思路,先找到,然后将指定人信息打印在屏幕上。


(4)修改指定联系人

void ModifyContact(Contact* pc)
{
	assert(pc);
	char name[NAME_MAX] = { 0 };
	if (pc->sz == 0)
	{
		printf("通讯录为空,无法修改\n");
		return;
	}
	printf("请输入你想修改的联系人的姓名:>");
	scanf("%s", name);
	int pos = FindContact(pc, name);
	if (-1 == pos)
	{
		printf("通讯录中没有此人\n");
		return;
	}
	printf("请输入姓名:>");
	scanf("%s", pc->data[pos].name);
	printf("请输入年龄:>");
	scanf("%d", &pc->data[pos].age);
	printf("请输入性别:>");
	scanf("%s", pc->data[pos].sex);
	printf("请输入地址:>");
	scanf("%s", pc->data[pos].addr);
	printf("请输入电话:>");
	scanf("%s", pc->data[pos].tele);
	printf("修改完成\n");
}

同删除指定联系人一样的思路,先找到,然后将指定人要修改的信息替换过去。


(5)显示通讯录的信息

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

 用for循环,将所有联系人的信息打印在屏幕上。


(6)清空所有联系人

void EmptyContact(Contact* pc)
{
	assert(pc);
	pc->sz = 0;
	memset(pc->data, 0, sizeof(pc->data));
	printf("联系人已清空\n");
}

 将联系人个数sz置为0,用memset函数将pc指向的data数组的sizeof(pc->data)个字节置为0


(7)以名字排序所有联系人

void SortContact(Contact* pc)
{
	int i = 0;
	int j = 0;
	struct PeoInfo temp;
	for (i = 0; i < pc->sz - 1; i++)
		for (j = 0; j < pc->sz - 1 - i; j++)
		{
			if (strcmp(pc->data[j].name, pc->data[j + 1].name) > 0)
			{
				temp = pc->data[j];
				pc->data[j] = pc->data[j + 1];
				pc->data[j + 1] = temp;
			}
		}
	printf("排序完成\n");
}

定义一个结构体数组temp, 利用冒泡排序的思想进行排序

    strcmp函数 来比较拼音顺序

  • 如果返回值小于 0,则表示 str1 小于 str2。
  • 如果返回值大于 0,则表示 str1 大于 str2。
  • 如果返回值等于 0,则表示 str1 等于 str2。

三.通讯录的优化

1.动态增容

为了节省空间,更高效的利用空间,我们采用动态的开辟空间,即根据我们的需要,

去开辟一定大小的空间,而不是直接开辟空间去使用

 

 我们要对创建的结构体进行修改,增加capacity变量来记录当前通讯录的最大容量。

void check_capacity(Contact* pc)
{
	if (pc->sz == pc->capacity)
	{
		//增加容量
		PeoInfo* ptr = (PeoInfo*)realloc(pc->data, (pc->capacity + INC_SZ) * sizeof(PeoInfo));
		if (ptr == NULL)
		{
			perror("check_capacity::realloc");
			return;
		}
		pc->data = ptr;
		pc->capacity += INC_SZ;
		printf("增容成功\n");
	}
}

 定义一个函数check_capacity进行动态开辟空间。

如果联系人个数等于通讯录最大容量,则进行增容。用realloc函数,为data开辟(pc->capacity + INC_SZ) * sizeof(PeoInfo) ((最大容量+要增加的)*(一个联系人结构体的大小))字节的空间。


(1)初始化通讯录

//静态版本
//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;
	PeoInfo* ptr = (PeoInfo*)calloc(DEFAULT_SZ, sizeof(PeoInfo));
	if (ptr == NULL)
	{
		perror("InitContact::calloc");
		return;
	}
	pc->data = ptr;
	pc->capacity = DEFAULT_SZ;
}

 在初始化的时候就要开辟空间,为后面使用做准备。


(2)增加联系人

void AddContact(Contact* pc)
{
	assert(pc);
	check_capacity(pc);
	//增加人的信息
	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].addr);
	printf("请输入电话:>");
	scanf("%s", pc->data[pc->sz].tele);
	pc->sz++;
}

 动态版的AddContact函数不需要判断通讯录是否满了,调用check_capacity函数,如果内存满了则增容,然后再添加联系人信息。


(3)清空所有联系人

void EmptyContact(Contact* pc)
{
	assert(pc);
	pc->sz = 0;
	memset(pc->data, 0, sizeof(pc->data));
	pc->capacity=0;//
	printf("联系人已清空\n");
}

在此函数中,再加上capacity置为0即可。


2.写入文件

为了我们通讯录能够保存数据,在我们下次启动程序时仍然能够使用,我们引入文件,

将联系人信息存到文本文件中,运行程序先打开文件,然后读取,再可以对其进行修改,

最后退出前,将信息保存到文件中。

(1)初始化时,读取文件信息

void InitContact(Contact* pc)
{
	assert(pc);
	pc->sz = 0;
	PeoInfo* ptr = (PeoInfo*)calloc(DEFAULT_SZ, sizeof(PeoInfo));
	if (ptr == NULL)
	{
		perror("InitContact::calloc");
		return;
	}
	pc->data = ptr;
	pc->capacity = DEFAULT_SZ;

	//加载文件信息到通讯录
	LoadContact(pc);
}

 初始化之后再通过LoadContact函数,将文件中的信息加载到通讯录中。


      LoadContact函数 

void LoadContact(Contact* pc)
{
	//读数据
	//1.打开文件
	FILE* pf = fopen("contact.txt", "rb");
	if (NULL == pf)
	{
		perror("LoadContact");
	}
	else
	{
		//2.读数据
		PeoInfo tmp = { 0 };
		int i = 0;
		while (fread(&tmp, sizeof(PeoInfo), 1, pf))
		{
			check_capacity(pc);
			pc->data[i] = tmp;
			pc->sz++;
			i++;
		}
		fclose(pf);
		pf = NULL;
	}

}

 用FILE*类型的pf接收"contact.txt"的信息,用fopen函数选择“rb"(以二进制打开,读文件),打开如果能成功打开,再循环使用fread函数,读取文件,读取完后用fclose函数关闭文件,再将pf置为NULL,防止数据丢失。

(2)退出前,将信息保存到文件中

void SaveContact(Contact* pc)
{
	//写数据
	//1,打开文件
	FILE* pf=fopen("contact.txt", "wb");
	if (NULL == pf)
	{
		perror("SaveContact");
	}
	else
	{
		//写数据
		int i = 0;
		for (i = 0; i < pc->sz; i++)
		{
			fwrite(pc->data + i,sizeof(PeoInfo),1,pf);
		} 
        fclose(pf);
	    pf = NULL;
	} 	
	printf("保存完成\n");
}

 用FILE*类型的pf接收"contact.txt"的信息,用fopen函数选择“wb"(以二进制打开,写文件),打开如果能成功打开,再循环使用fwrite函数,将数据保存到文件中,保存完后用fclose函数关闭文件,再将pf置为NULL,防止数据丢失。


总结

本文只实现了通讯录的部分功能,从静态版本到动态版本,再到文件版本,一步步修改完善。我们在完成一些比较复杂的项目时,就该由易到难,将问题分解化、细化,再一步一步的解决,最后完成整个项目。也开动脑筋想想,看看哪些地方还可以优化,想想一个问题的多种解法,也可以将代码进行完善,实现更多功能。


源代码

   contact.h

#pragma once

#include<stdio.h>
#include<string.h>
#include<assert.h>
#include<stdlib.h>

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

#define DEFAULT_SZ 3
#define INC_SZ 2

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

//静态版本
//typedef struct Contact
//{
//	PeoInfo data[MAX];
//	int sz;
//}Contact;

//动态版本
typedef struct Contact
{
	PeoInfo* data;//指向存放人信息的空间
	int sz;//当前已经放好信息的个数
	int capacity;//当前通讯录最大容量
}Contact;

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

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

//显示通讯录的信息
void ShowContact(const Contact* pc);

//添加通讯录联系人
void AddContact(Contact* pc);

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

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

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

//清空所有联系人
void EmptyContact(Contact* pc);

//以名字排序所有联系人
void SortContact(Contact* pc);

//保存通讯录的信息到文件中
void SaveContact(Contact* pc);

//加载文件信息到通讯录
void LoadContact(Contact* pc);

 contact.c

#define _CRT_SECURE_NO_WARNINGS 1

#include"contact.h"

//静态版本
//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;
	PeoInfo* ptr = (PeoInfo*)calloc(DEFAULT_SZ, sizeof(PeoInfo));
	if (ptr == NULL)
	{
		perror("InitContact::calloc");
		return;
	}
	pc->data = ptr;
	pc->capacity = DEFAULT_SZ;

	//加载文件信息到通讯录
	LoadContact(pc);
}

//销毁通讯录
void DestroyContact(Contact* pc)
{
	free(pc->data);
	pc->data = NULL;
	pc->capacity = 0;
	pc->sz = 0;
	pc = NULL;
}

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

//静态版本
//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].addr);
//	printf("请输入电话:>");
//	scanf("%s", pc->data[pc->sz].tele);
//	pc->sz++;
//}

//增容
void check_capacity(Contact* pc)
{
	if (pc->sz == pc->capacity)
	{
		//增加容量
		PeoInfo* ptr = (PeoInfo*)realloc(pc->data, (pc->capacity + INC_SZ) * sizeof(PeoInfo));
		if (ptr == NULL)
		{
			perror("check_capacity::realloc");
			return;
		}
		pc->data = ptr;
		pc->capacity += INC_SZ;
		printf("增容成功\n");
	}
}

//动态版本
void AddContact(Contact* pc)
{
	assert(pc);
	check_capacity(pc);

	//增加人的信息
	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].addr);
	printf("请输入电话:>");
	scanf("%s", pc->data[pc->sz].tele);
	pc->sz++;
}
int FindContact(const Contact* pc, char name[])
{
	int i = 0;
	for (i = 0; i < pc->sz; i++)
	{
		if (strcmp(pc->data[i].name, name) == 0)
		{
			return i;
		}
	}
	return -1;
}

void DelContact(Contact* pc)
{
	assert(pc);
	char name[NAME_MAX] = { 0 };
	if (pc->sz == 0)
	{
		printf("通讯录为空,无法删除\n");
		return;
	}
	printf("请输入你想删除的联系人的姓名:>");
	scanf("%s", name);
	int ret = FindContact(pc, name);
	if (-1 == ret)
	{
		printf("通讯录中没有此人\n");
		return;
	}
	int i = 0;
	for (i = ret; i < pc->sz - 1; i++)
	{
		pc->data[i] = pc->data[i + 1];
	}
	pc->sz--;
	printf("删除成功\n");
}

void SearchContact(const Contact* pc)
{
	assert(pc);
	char name[NAME_MAX] = { 0 };
	if (pc->sz == 0)
	{
		printf("通讯录为空,无法查找\n");
		return;
	}
	printf("请输入你想查找的联系人的姓名:>");
	scanf("%s", name);
	int pos = FindContact(pc, name);
	if (-1 == pos)
	{
		printf("通讯录中没有此人\n");
		return;
	}
	printf("%-20s\t%-4s\t%-5s\t%-20s\t%-12s\n", "名字", "年龄", "性别", "地址", "电话");
	printf("%-20s\t%-4d\t%-5s\t%-20s\t%-12s\n",
		pc->data[pos].name,
		pc->data[pos].age,
		pc->data[pos].sex,
		pc->data[pos].addr,
		pc->data[pos].tele);
}

void ModifyContact(Contact* pc)
{
	assert(pc);
	char name[NAME_MAX] = { 0 };
	if (pc->sz == 0)
	{
		printf("通讯录为空,无法修改\n");
		return;
	}
	printf("请输入你想修改的联系人的姓名:>");
	scanf("%s", name);
	int pos = FindContact(pc, name);
	if (-1 == pos)
	{
		printf("通讯录中没有此人\n");
		return;
	}
	printf("请输入姓名:>");
	scanf("%s", pc->data[pos].name);
	printf("请输入年龄:>");
	scanf("%d", &pc->data[pos].age);
	printf("请输入性别:>");
	scanf("%s", pc->data[pos].sex);
	printf("请输入地址:>");
	scanf("%s", pc->data[pos].addr);
	printf("请输入电话:>");
	scanf("%s", pc->data[pos].tele);
	printf("修改完成\n");
}

void EmptyContact(Contact* pc)
{
	assert(pc);
	pc->sz = 0;
	memset(pc->data, 0, sizeof(pc->data));
	pc->capacity=0;//
	printf("联系人已清空\n");
}

void SortContact(Contact* pc)
{
	int i = 0;
	int j = 0;
	struct PeoInfo temp;
	for (i = 0; i < pc->sz - 1; i++)
		for (j = 0; j < pc->sz - 1 - i; j++)
		{
			if (strcmp(pc->data[j].name, pc->data[j + 1].name) > 0)
			{
				temp = pc->data[j];
				pc->data[j] = pc->data[j + 1];
				pc->data[j + 1] = temp;
			}
		}
	printf("排序完成\n");
}

void SaveContact(Contact* pc)
{
	//写数据
	//1,打开文件
	FILE* pf=fopen("contact.txt", "wb");
	if (NULL == pf)
	{
		perror("SaveContact");
	}
	else
	{
		//写数据
		int i = 0;
		for (i = 0; i < pc->sz; i++)
		{
			fwrite(pc->data + i,sizeof(PeoInfo),1,pf);
		} 
        fclose(pf);
	    pf = NULL;
	} 	
	printf("保存完成\n");
}

void LoadContact(Contact* pc)
{
	//读数据
	//1.打开文件
	FILE* pf = fopen("contact.txt", "rb");
	if (NULL == pf)
	{
		perror("LoadContact");
	}
	else
	{
		//2.读数据
		PeoInfo tmp = { 0 };
		int i = 0;
		while (fread(&tmp, sizeof(PeoInfo), 1, pf))
		{
			check_capacity(pc);
			pc->data[i] = tmp;
			pc->sz++;
			i++;
		}
		fclose(pf);
		pf = NULL;
	}

}

 test.c

#define _CRT_SECURE_NO_WARNINGS 1

#include"contact.h"

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

enum Option
{
	EXIT,//0
	ADD,//1
	DEL,
	SEACHER,
	MODIFY,
	SHOW,
	EMPTY,
	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:
			DelContact(&con);
			break;
		case SEACHER:
			SearchContact(&con);
			break;
		case MODIFY:
			ModifyContact(&con);
			break;
		case SHOW:
			ShowContact(&con);
			break;
		case EMPTY:
			EmptyContact(&con);
			break;
		case SORT:
			SortContact(&con);
			break;
		case EXIT:
			//保存通讯录信息到文件中
			SaveContact(&con);
			DestroyContact(&con);
			printf("退出通讯录\n");
			break;
		default:
			printf("选择错误,请重新选择\n");
			break;
		}
	} while (input);
	return 0;
}

 

希望本文对你有所帮助,感谢阅读,愿与君共勉。

  • 15
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 18
    评论
评论 18
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

浪味仙h

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值