C语言如何优化通讯录(动态扩容)

前言

本文章重在讲述如何通讯录(存储内容的空间有限)优化成随着录入信息不断地增加动态开辟空间的通讯录。


提示:以下是本篇文章正文内容,下面案例可供参考

一、首先是创建结构体成员变量

1.创建一个含有联系人信息的结构体:

struct PeoInfo 
{
	char name[20];
	char sex[5];
	int age;
	char phonenumber[11];
	char address[30];
};

2.创建一个保存已录用联系人信息的结构体

struct Contact
{
	struct PeoInfo* data;//指向PeoInfo结构体的指针
	int sz;//已经放进多少组的信息	
	int capacity;//当前容量
};

二.明白动态内存函数的使用(malloc 、realloc、memset)

1.malloc

//该函数原型如下
void* malloc (size_t size);

 这个函数向内存申请一块连续可用的空间,并返回指向这块空间的指针。

  • 如果开辟成功,则返回一个指向开辟好空间的指针。

  • 如果开辟失败,则返回一个NULL指针,因此malloc的返回值一定要做检查。

  • 返回值的类型是 void* ,所以malloc函数并不知道开辟空间的类型,具体在使用的时候使用者自己来决定。

  • 如果参数 size 为0,malloc的行为是标准是未定义的,取决于编译器。

2.realloc

//该函数原型如下
void* realloc (void* ptr, size_t size);
  • ptr 是要调整的内存地址

  • size 调整之后新大小

  • 返回值为调整之后的内存起始位置。

  • 这个函数调整原内存空间大小的基础上,还会将原来内存中的数据移动到 新 的空间。

  • realloc在调整内存空间的是存在两种情况:

  • 情况1:原有空间之后有足够大的空间

    • 情况1:原有空间之后有足够大的空间

    • 情况2:原有空间之后没有足够大的空间4b72a9b14ad14f00814daaac0ffda795.png

3.memset 

//该函数原型如下
void * memset ( void * ptr, int value, size_t num );

 将 ptr 所指向的内存块的前 num 个字节设置为指定的值(解释为无符号字符)。 (此为机翻,若要详细了解memset的使用可以自行搜索。)

三.如何动态分配空间?

我们希望一开始先分配能存储三个联系人信息的空间:值得注意的是,如果我们不首先对指针con.data指向的数组开辟空间,memset函数是无法对所指向的空间进行初始化。

    struct Contact con;	
	con.data = (struct PeoInfo* )malloc(3 * sizeof(struct PeoInfo));

 开辟好空间后我们需要对这个空间初始化: 

void InitContact(struct Contact* pc)
{
	pc->sz = 0;
	pc->capacity = 3;
	//希望开始先动态分配能存储三个联系人信息的空间
	memset(pc->data, 0, 3 * sizeof(pc->data[0]));
};

四.主函数设计

int main()
{
	int input = 0;
	struct Contact con;	
	con.data = (struct PeoInfo* )malloc(3 * sizeof(struct PeoInfo));
	InitContact(&con);
	do

	{
		menu();
		printf("请选择\n");
		scanf("%d", &input);
		switch (input)
		{
		case 1:
			AddContact(&con);
			break;
		case 2:
			DelContact(&con);
			break;
		case 3:
			SerchContact(&con);
			break;
		case 4:
			ModifyContact(&con);
			break;
		case 5:
			ShowContact(&con);
			break;
		case 6:
			ClearContact(&con);
			break;
		case 7:
			SortContact(&con);
			break;
		case 0:
			printf("退出成功");
			break;
		default:
			printf("输入错误,请重新输入\n");
			break;
		}
	} while (input);
	free(con.data);
	con.data = NULL;
	return 0;
}

值得注意的是:当前空间是由我们自己(malloc)开辟的,所以当使用完后需要释放此空间,并将该指针置为NULL。 

 五.功能函数的设计

1.添加用户(AddContact)

void AddContact(struct Contact* pc)
{
		printf("请输入姓名\n");
		scanf("%s", pc->data[pc->sz].name);
		printf("请输入电话\n");
		scanf("%s", pc->data[pc->sz].phonenumber);
		printf("请输入年龄\n");
		scanf("%d", &(pc->data[pc->sz].age));
		printf("请输入住址\n");
		scanf("%s", pc->data[pc->sz].address);
		printf("请输入性别\n");
		scanf("%s", pc->data[pc->sz].sex);
		pc->sz++;
		printf("增加成功\n");
	if (pc->sz == pc->capacity)
	{
		pc->data = (struct PeoInfo*)realloc(pc->data, (pc->sz + 3) * sizeof(struct PeoInfo));
		pc->capacity += 3;
	}
}

函数说明:每录用一次联系人的信息,都会对当前已录用联系人的个数以及当前容量进行判断,如果发现联系人个数和容量相等时,即空间已满,使用realloc函数再给它多分配三个联系人的空间 ,如此反复。

2. 显示用户

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

对联系人数组进行遍历打印即可。

 3.查找用户

static int FindPeople(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 SerchContact(const struct Contact* pc)
{
	char name[20] = "";
	printf("请输入要查找人的姓名\n");
	scanf("%s", name);
	int i = FindPeople(pc, name);
	if (i != -1)
	{
		printf("%-20s\t%-5s\t%-5s\t%-12s\t%-30s\n", "姓名", "性别", "年龄", "电话", "地址");
		printf(" % -20s\t % -5s\t % -5d\t % -12s\t % -30s\n", pc->data[i].name,
			pc->data[i].sex,
			pc->data[i].age,
			pc->data[i].phonenumber,
			pc->data[i].address);
	}
	else
		printf("为查询到此人\n");
}

 在下面的查找函数中调用FindPeople函数,并接收它的返回值。

4.修改联系人

void ModifyContact(struct Contact* pc)
{
	char name[20] = "";
	printf("请输入要修改人的姓名\n");
	scanf("%s", name);
	int i = FindPeople(pc, name);
	if (i != -1)
	{
		printf("请输入姓名\n");
		scanf("%s", pc->data[i].name);
		printf("请输入电话\n");
		scanf("%s", pc->data[i].phonenumber);
		printf("请输入年龄\n");
		scanf("%d", &(pc->data[i].age));
		printf("请输入住址\n");
		scanf("%s", pc->data[i].address);
		printf("请输入性别\n");
		scanf("%s", pc->data[i].sex);
		printf("修改成功\n");
	}
	else
		printf("未查询到此人\n");
}

使用FindPeople函数找到数组中此联系人的下标,对它进行修改即可 

5. 排序联系人

static int Compair(const void* a, const void* b)
{
	return strcmp(((struct PeoInfo*)a)->name, ((struct PeoInfo*)b)->name);
}

void SortContact(struct Contact* pc)
{
	qsort(pc->data, pc->sz, sizeof(struct PeoInfo), Compair);
}

使用联系人的姓名进行排序,qosrt中的比较函数为自行写的Compair 函数。

6. 删除联系人

void DelContact(struct Contact* pc)
{
	char name[20] = " ";
	printf("请输入要删除的联系人");
	scanf("%s", name);
	int i = FindPeople(pc, name);
	if (i != -1)
	{
		int j = 0;
		for (j = i; j < pc->sz - 1; j++)
		{
			pc->data[j] = pc->data[j + 1];
		}
		pc->sz--;
		printf("成功删除指定联系人\n");
	}
}

7. 清空联系人

void ClearContact(struct Contact* pc)
{
	memset(pc->data, 0, pc->capacity * sizeof(struct PeoInfo));
	pc->sz = 0;
}

利用memset函数将当前联系人数组所占空间全部置为0。

总结

  1. 保存已录用联系人信息的结构体中,可以设置一个指向联系人结构体的指针,利用该指针对联系人结构体进行操作。
  2. 创建了结构体成员变量后,需要对其先开辟空间后才可以对内存进行初始(memset)
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值