通讯录的实现(超详细)——C语言(进阶)

news2024/11/13 14:28:39

       

目录

一、创建联系人信息(结构体)

二、创建通讯录(结构体)

三、define定义常量

四、打印通讯录菜单

五、枚举菜单选项

六、初始化通讯录

七、实现通讯的的功能

7.1 增加加联系人

7.2 显示所有联系人的信息

​7.3 单独查找人的函数

7.4 删除指定联系人

7.5 查找指定联系人

7.6 修改指定联系人

7.7 按照名字顺序进行排序

7.8  清空所有联系人

八、通讯录优化——静态->动态

8.1 通讯录结构体优化

8.2 初始化函数的优化

8.3增加联系人的优化

8.4 释放通讯录的空间

九、完整代码 

test.c

contact.h

contact.c


实现一个通讯录,这里我们先来简单构思一下,通讯录中保存人的信息,分别有姓名,年龄,性别,电话,住址,假设我们通讯录中可以存放1000个人的信息。同时我们通讯录还要具备一些功能。包括;

①  增加联系人

②  删除指定联系人

③  修改指定联系人

④  查找指定联系人

⑤  显示所有联系人的信息

⑥  按照名字顺序进行排序

⑦  清空所有联系人

在写完之后,我们紧接着可以对通讯录进行优化,将静态通讯录改为动态通讯录。

一起跟着博主的思路来完成通讯录的实现吧!

        首先我们需要三个文件,分别是test.c——测试通讯录,contact.h——函数和类型的声明,contact.c——函数的实现,其次我们需要创建保存人信息的结构体。接下来我们开始慢代码实现吧!

一、创建联系人信息(结构体)

        为了保存联系人的各个信息,我们创建了一个结构体,放在头文件中,同时为了方便使用,对结构体重命名。

typedef struct PeoInfo
{
	char name[20];
	int age;
	char sex[5];
	char tele[12];
	char addr[30];
}PeoInfo;

二、创建通讯录(结构体)

为了方便记录通讯录中现在的人数,创建一个结构体将联系人结构体和人数封装在一起。

//通讯录
typedef struct Contact
{
	PeoInfo data[100];
	int sz;
}Contact;

三、define定义常量

写到这里,我们发现如果以后想要更改通讯录的人数,或者名字的宽度,以及地址的宽度这些变量,要到代码中修改,很麻烦,我们可以通过define定义常量,这样使用或者更改的时候就会很方便,达到我们想要的效果。

#define MAX 100   //最大人数
#define MAX_NAME 20  //名字最大宽度
#define MAX_SEX 5  //性别种类
#define MAX_TELE 12  //电话最大长度
#define MAX_ADDR 30  //地址最大宽度

四、打印通讯录菜单

因为每次使用至少使用一次,所以我们采用do—while循环来设计测试通讯录。

void menu()
{
	printf("*******************************\n");
	printf("********1.add      2.del*******\n");
	printf("********3.search   4.modify****\n");
	printf("********5.show     6.sort******\n");
	printf("*********    7.clear***********\n");
	printf("*********    0.exit ***********\n");
	printf("*******************************\n");
}
void test()
{
	int input = 0;
	do
	{
		menu();
		printf("请选择:> ");
		scanf("%d", &input);
	} while(input);
}

五、枚举菜单选项

为了代码美观,以及更方便的去识别代码的意思,我们可以采用自定义枚举的方式来实现功能选择。具体代码如下

enum Option
{
	Exit,//0   ——退出
	Add,//1    ——增加联系人
	Del,//2    ——删除指定联系人
	Search,//3 ——查找指定联系人信息
	Modify,//4 ——修改指定联系人信息
	Show,//5   ——显示通讯录中所有联系人
	Sort,//6   ——排序联系人
	Clear//7   ——清空所有联系人

};

 这样就容易理解许多,效果如下所示:

void test()
{
	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 Search:
			SearchContact(&con);
			break;
		case Modify:
			ModifyContact(&con);
			break;
		case Show:
			ShowContact(&con);
			break;
		case Sort:
			SortContact(&con);
			break;
		case Clear:
			ClearContact(&con);
			break;
		case Exit:
			printf("退出通讯录\n");
			break;
		default:
			printf("选择错误,请重新选择\n");
			break;
		}
	} while (input);
}

六、初始化通讯录

当我们创建完通讯录之后,为了更好的实现后面的功能,最好初始化一下通讯录。

注意:在contact.h中声明,在contact.c中实现。

        这里博主使用memset来讲通讯录中的信息全部初始化为0,如果不想使用memset,也可以采用循环的形式来初始化。具体代码如下:

//初始化通讯录
void InitContact(Contact* pc)
{
	memset(pc->data, 0, sizeof(pc->data));
	pc->sz = 0;
}

七、实现通讯的的功能

注意:①以下函数的实行都是在contact.h中声明类型,然后在contact.v中实现

           ②在进入函数时,需要assert进行断言,防止传入空指针

           ③如果要进行的操作不需要更改通讯录的内容(例如:显示所有联系人)时,要用const修饰以下,保护通讯录内容。

7.1 增加加联系人

增加联系人我们首先需要判断通讯录里面的人数是否满了。没满才能继续进行操作

//增加联系人
void AddContact(Contact* pc)
{
	assert(pc);//断言,防止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("成功添加联系人");

}

7.2 显示所有联系人的信息

当我们增加完联系人之后,我们想要看看是否成功添加,来看看通讯录中存在的联系人。

注意:我们打印的时候可以借助\t制表符来进行打印,这样打印出来会很整齐,很好看!

//显示所有联系人
void ShowContact(const Contact* pc)
{
	//断言
	assert(pc);
	//打印列标题
	printf("%-10s\t%-4s\t%-5s\t%-12s\t%-30s\n","姓名","年龄","性别","电话","地址");
	int i = 0;
	//打印数据
	for (i = 0; i < pc->sz; i++)
	{
		printf("%-10s\t%-4d\t%-5s\t%-12s\t%-30s\n", pc->data[i].name,
			pc->data[i].age,
			pc->data[i].sex,
			pc->data[i].tele,
			pc->data[i].addr);
	}
}

具体效果如下图所示:

 7.3 单独查找人的函数

写到这里我们发现不管是删除联系人还是查找联系人以及修改联系人,都会经过查找这一步,所以单独写个查找的函数代码如下:

//只在本文件使用
static int FindName(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;
}

7.4 删除指定联系人

当我们写完单独查找人的函数后,这个删除指定联系人就会简单许多,在查找前仍然要检查一下通讯录是否为空,如果为空就没必要再继续下去了,先查找到指定联系人,看看是否存在,然后再删除,具体代码如下:

//删除指定联系人
void DelContact(Contact* pc)
{
	if (pc->sz == 0)
	{
		printf("通讯录为空,无法删除\n");
		return;
	}
	char name[MAX_NAME]={0};
	assert(pc);
	//删除
	printf("请输入要删除人的名字:");
	scanf("%s", name);
	// 不管是删除联系人还是查找联系人以及修改联系人,都会经过查找这一步,所以单独写个查找的函数
	int del=FindName(pc, name);
	if (del == -1)
	{
		printf("要删除的人不存在\n");
		return;
	}
	//删除所要删除的联系人
	int i = 0;
	for (i = del; i < pc->sz-1; i++)
	{
		pc->data[i] = pc->data[i + 1];
	}
	//人数减一
	pc->sz--;

	printf("成功删除联系人\n");
}

7.5 查找指定联系人

直接调用单独查找人的函数即可,是不是很方便!如果查找的人不存在,那就直接跳出即可,如果找到,就答应查找的联系人,代码如下:

//查找指定联系人
void SearchContact(const Contact* pc)
{
	char name[MAX_NAME] = { 0 };
	assert(pc);
	printf("请输入要查找人的名字:");
	scanf("%s", name);
	int pos = FindName(pc, name);
	if (pos == -1)
	{
		printf("要查找的人不存在\n");
	}
	else
	{
		printf("%-10s\t%-4s\t%-5s\t%-12s\t%-30s\n", "姓名", "年龄", "性别", "电话", "地址");
		printf("%-10s\t%-4d\t%-5s\t%-12s\t%-30s\n", pc->data[pos].name,
			pc->data[pos].age,
			pc->data[pos].sex,
			pc->data[pos].tele,
			pc->data[pos].addr);
	}
}

7.6 修改指定联系人

修改联系人很简单,这里就不多做解释啦,直接上代码!

//修改联系人
void ModifyContact(Contact* pc)
{
	char name[MAX_NAME] = { 0 };
	assert(pc);
	printf("请输入要修改联系人的姓名:");
	scanf("%s", name);
	int pos = FindName(pc, name);
	if (pos == -1)
	{
		printf("要修改的联系人不存在\n");
	}
	else
	{
		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].tele);
		printf("请输入地址:");
		scanf("%s", pc->data[pos].addr);
	}
}

7.7 按照名字顺序进行排序

这里博主就拿按照名字顺序进行排序,利用库函数qsort函数进行排序,具体qsort函数是什么,博主这里建议大家去查一查,了解一下,当然小编也准备单独写一篇博客来介绍qsort函数以及qsort的模拟实现,如果感兴趣,可以关注,期待小编更新哦。

int cmp_name(const void* p1, const void* p2)
{
	return strcmp(((PeoInfo*)p1)->name, ((PeoInfo*)p2)->name);
}
//排序联系人
void SortContact(Contact* pc)
{
	assert(pc);
	//就拿按照名字排序吧
	//利用qsort函数
	qsort(pc->data, pc->sz, sizeof((pc->data)[0]), cmp_name);
	//排序结束,输出通讯录
	//打印列标题
	printf("%-10s\t%-4s\t%-5s\t%-12s\t%-30s\n", "姓名", "年龄", "性别", "电话", "地址");
	int i = 0;
	//打印数据
	for (i = 0; i < pc->sz; i++)
	{
		printf("%-10s\t%-4d\t%-5s\t%-12s\t%-30s\n", pc->data[i].name,
			pc->data[i].age,
			pc->data[i].sex,
			pc->data[i].tele,
			pc->data[i].addr);
	}
}

7.8  清空所有联系人

清空联系人也会很简单,就直接讲通讯录里面的sz人数置为0即可,具体代码如下

void ClearContact(Contact* pc)
{
	assert(pc);
	//其实清空联系人只需要把里面的人数清零即可
	int i = 0;
	printf("确定要清空所有联系人吗?确定请按1,按其余键返回\n");
	scanf("%d", &i);
	if (i == 1)
	{
		pc->sz = 0;
		printf("清空联系人成功");
	}
}

八、通讯录优化——静态->动态

写到这里,其实简单的通讯录已经介绍完毕,但是我们这个通讯录其实可以进行优化的。

优化目标:

                ①通讯录空间不是固定的,大小可以调整的。

                ②默认能放三个人的信息,如果不够,就每次增加两个人的容量

8.1 通讯录结构体优化

因为这里的通讯录人数不是固定的了,所以我们首先想到的是优化通讯录这个结构。通讯录的空间是动态开辟的,由malloc开辟即可。

注意:①sz是记录当前放的有效元素的个数

            ②capacity是记录通讯录当前最大容量

#define DEFAULT_SZ 3  //起始容量
#define ADD_SZ 2    //每次需要增加的容量

//动态版本

//通讯录容量可以更改,不够时进行增加
typedef struct contact
{
	PeoInfo* data;//指向存放数据的空间
	int sz;//当前放的有效元素的个数
	int capacity;//通讯录当前最大容量
}Contact;

8.2 初始化函数的优化

初始化函数也不能是固定的100人全部初始化。而是应该最开始开辟三个人的空间。人数为0,容量为3。

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

8.3增加联系人的优化

这时动态版本的增加联系人就不存在满的问题了,而是先检查人数是否等于这里的最大容量的,如果等于,那就需要进行扩容了。(利用realloc函数)这里的好处就体现出来了,我们用多少空间,就开辟多少空间,每次只多开辟两个人的空间即可。

我们这里用int来接收增容的结果,如果增容成功,就返回1,增容失败就返回0,然后在进行判断,如果失败,就没必要继续往下走了。

//动态版本
void AddContact(Contact* pc)
{
	assert(pc);//断言,防止pc是空指针
	CheckCapacity(pc);
	if (0 == CheckCapacity(pc))
	{
		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");

}
int CheckCapacity(Contact* pc)
{
	assert(pc);
	//判断通讯录是否满了
	if (pc->sz == pc->capacity)
	{
		PeoInfo* ptr=(PeoInfo*)realloc(pc->data, (pc->capacity+ADD_SZ)*sizeof(PeoInfo));
		if (ptr == NULL)
		{
			perror("CheckCapacity");
			return 0;
		}
		else
		{
			pc->data = ptr;
			pc->capacity += ADD_SZ;
			printf("增容成功\n");
			return 1;
		}
	}
	return 1;
}

8.4 释放通讯录的空间

因为这里的通讯录是动态开辟,所以当我们使用完之后要将开辟的内存释放掉,防止内存泄漏。

当然释放完空间,我们里面的信息也就没有了,这时要把人数置为0,容量变为3.

//因为通讯录是动态开辟的,所以使用完需要释放
void DestroyContact(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.add      2.del*******\n");
	printf("********3.search   4.modify****\n");
	printf("********5.show     6.sort******\n");
	printf("**********   7.clear***********\n");
	printf("*********    0.exit************\n");
	printf("*******************************\n");
}
void test()
{
	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 Search:
			SearchContact(&con);
			break;
		case Modify:
			ModifyContact(&con);
			break;
		case Show:
			ShowContact(&con);
			break;
		case Sort:
			SortContact(&con);
			break;
		case Clear:
			ClearContact(&con);
			break;
		case Exit:
			DestroyContact(&con);
			printf("退出通讯录\n");
			break;
		default:
			printf("选择错误,请重新选择\n");
			break;
		}
	} while (input);
}
int main()
{
	test();
	return 0;
}

contact.h

#define _CRT_SECURE_NO_WARNINGS 1

#pragma once

#define MAX 100
#define MAX_NAME 20
#define MAX_SEX 5
#define MAX_TELE 12
#define MAX_ADDR 30

#define DEFAULT_SZ 3
#define ADD_SZ 2

#include<string.h>

#include<stdio.h>

#include<assert.h>

#include<stdlib.h>


//类型的声明

enum Option
{
	Exit,//0
	Add,//1
	Del,//2
	Search,//3
	Modify,//4
	Show,//5
	Sort,//6
	Clear//7

};

typedef struct PeoInfo
{
	char name[MAX_NAME];
	int age;
	char sex[MAX_SEX];
	char tele[MAX_TELE];
	char addr[MAX_ADDR];
}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 AddContact(Contact* pc);

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

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

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

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

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


//清空联系人
void ClearContact(Contact* pc);

//释放通讯录的空间
void DestroyContact(Contact* pc);

contact.c

#define _CRT_SECURE_NO_WARNINGS 1

#define _CRT_SECURE_NO_WARNINGS 1
#include"contact.h"
//函数的实现

//静态版本
初始化通讯录
//void InitContact(Contact* pc)
//{
//	memset(pc->data, 0, sizeof(pc->data));
//	pc->sz = 0;
//}

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


//静态版本
//增加联系人
//void AddContact(Contact* pc)
//{
//	assert(pc);//断言,防止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("成功添加联系人");
//
//}

//动态版本
int CheckCapacity(Contact* pc)
{
	assert(pc);
	//判断通讯录是否满了
	if (pc->sz == pc->capacity)
	{
		PeoInfo* ptr=(PeoInfo*)realloc(pc->data, (pc->capacity+ADD_SZ)*sizeof(PeoInfo));
		if (ptr == NULL)
		{
			perror("CheckCapacity");
			return 0;
		}
		else
		{
			pc->data = ptr;
			pc->capacity += ADD_SZ;
			printf("增容成功\n");
			return 1;
		}
	}
	return 1;
}
void AddContact(Contact* pc)
{
	assert(pc);//断言,防止pc是空指针
	CheckCapacity(pc);
	if (0 == CheckCapacity(pc))
	{
		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 ShowContact(const Contact* pc)
{
	//断言
	assert(pc);
	//打印列标题
	printf("%-10s\t%-4s\t%-5s\t%-12s\t%-30s\n", "姓名", "年龄", "性别", "电话", "地址");
	int i = 0;
	//打印数据
	for (i = 0; i < pc->sz; i++)
	{
		printf("%-10s\t%-4d\t%-5s\t%-12s\t%-30s\n", pc->data[i].name,
			pc->data[i].age,
			pc->data[i].sex,
			pc->data[i].tele,
			pc->data[i].addr);
	}
}

//只在本文件使用
static int FindName(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)
{
	if (pc->sz == 0)
	{
		printf("通讯录为空,无法删除\n");
		return;
	}
	char name[MAX_NAME] = { 0 };
	assert(pc);
	//删除
	printf("请输入要删除人的名字:");
	scanf("%s", name);
	找到要删除的人
	//int i = 0;
	//int del = 0;
	//int flag = 0;
	//for (i = 0; i < pc->sz; i++)
	//{
	//	if (strcmp(pc->data[i].name, name)==0)
	//	{
	//		del = i;
	//		flag = 1;//找到了
	//		break;
	//	}
	//}
	//if (flag == 0)
	//{
	//	printf("要删除的人不存在\n");
	//	return;
	//}
	// 不管是删除联系人还是查找联系人以及修改联系人,都会经过查找这一步,所以单独写个查找的函数
	int del = FindName(pc, name);
	if (del == -1)
	{
		printf("要删除的人不存在\n");
		return;
	}
	//删除所要删除的联系人
	int i = 0;
	for (i = del; i < pc->sz - 1; i++)
	{
		pc->data[i] = pc->data[i + 1];
	}
	//人数减一
	pc->sz--;

	printf("成功删除联系人\n");
}


//查找指定联系人
void SearchContact(const Contact* pc)
{
	char name[MAX_NAME] = { 0 };
	assert(pc);
	printf("请输入要查找人的名字:");
	scanf("%s", name);
	int pos = FindName(pc, name);
	if (pos == -1)
	{
		printf("要查找的人不存在\n");
	}
	else
	{
		printf("%-10s\t%-4s\t%-5s\t%-12s\t%-30s\n", "姓名", "年龄", "性别", "电话", "地址");
		printf("%-10s\t%-4d\t%-5s\t%-12s\t%-30s\n", pc->data[pos].name,
			pc->data[pos].age,
			pc->data[pos].sex,
			pc->data[pos].tele,
			pc->data[pos].addr);
	}
}

//修改联系人
void ModifyContact(Contact* pc)
{
	char name[MAX_NAME] = { 0 };
	assert(pc);
	printf("请输入要修改联系人的姓名:");
	scanf("%s", name);
	int pos = FindName(pc, name);
	if (pos == -1)
	{
		printf("要修改的联系人不存在\n");
	}
	else
	{
		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].tele);
		printf("请输入地址:");
		scanf("%s", pc->data[pos].addr);
	}
}

int cmp_name(const void* p1, const void* p2)
{
	return strcmp(((PeoInfo*)p1)->name, ((PeoInfo*)p2)->name);
}
//排序联系人
void SortContact(Contact* pc)
{
	assert(pc);
	//就拿按照名字排序吧
	//利用qsort函数
	qsort(pc->data, pc->sz, sizeof((pc->data)[0]), cmp_name);
	//排序结束,输出通讯录
	//打印列标题
	printf("%-10s\t%-4s\t%-5s\t%-12s\t%-30s\n", "姓名", "年龄", "性别", "电话", "地址");
	int i = 0;
	//打印数据
	for (i = 0; i < pc->sz; i++)
	{
		printf("%-10s\t%-4d\t%-5s\t%-12s\t%-30s\n", pc->data[i].name,
			pc->data[i].age,
			pc->data[i].sex,
			pc->data[i].tele,
			pc->data[i].addr);
	}
}

//清空联系人

void ClearContact(Contact* pc)
{
	assert(pc);
	//其实清空联系人只需要把里面的人数清零即可
	int i = 0;
	printf("确定要清空所有联系人吗?确定请按1,按其余键返回\n");
	scanf("%d", &i);
	if (i == 1)
	{
		pc->sz = 0;
		printf("清空联系人成功");
	}
}

//因为通讯录是动态开辟的,所以使用完需要释放
void DestroyContact(Contact* pc)
{
	free(pc->data);
	pc->data = NULL;
	pc->capacity = 0;
	pc->sz = 0;
}

好啦,到这里,今天的博主给大家带来的通讯录到这里就结束啦,如果哪里有问题,欢迎在评论区留言。如果觉得小编写的还不错的,那么可以一键三连哦,您的关注点赞和收藏是对小编最大的鼓励。谢谢大家!!!

 

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

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

相关文章

【自动化运维】Ansible常见模块的运用

目录 一、Ansible简介二、Ansible安装部署2.1环境准备 三、ansible 命令行模块3.1&#xff0e;command 模块3.2&#xff0e;shell 模块3.3&#xff0e;cron 模块3.4&#xff0e;user 模块3.5&#xff0e;group 模块3.6&#xff0e;copy 模块3.7&#xff0e;file 模块8&#xff…

C++之观察者模式(发布-订阅)

目录 模式简介 介绍 优点 缺点 代码实现 场景说明 实现代码 运行结果 模式简介 观察者模式&#xff08;Observer Pattern&#xff09;&#xff0c;也叫我们熟知的发布-订阅模式。 它是一种行为型模式。 介绍 观察者模式主要关注的是对象的一对多的关系&#xff0c; …

4-3 Working with time series

本文所用数据下载 Data from a Washington, D.C., bike-sharing system reporting the hourly count of rental bikes in 2011–2012 in the Capital Bikeshare system, along with weather and seasonal information. Our goal will be to take a flat, 2D dataset and trans…

搭建网站 --- 快速WordPress个人博客并内网穿透发布到互联网

文章目录 快速WordPress个人博客并内网穿透发布到互联网 快速WordPress个人博客并内网穿透发布到互联网 我们能够通过cpolar完整的搭建起一个属于自己的网站&#xff0c;并且通过cpolar建立的数据隧道&#xff0c;从而让我们存放在本地电脑上的网站&#xff0c;能够为公众互联…

JS——输入输出语法数组的操作

JavaScript输入输出语法 目标&#xff1a;能写出常见的JavaScript输入输出语法 输出语法 语法1&#xff1a; document.write(要输出的内容)作用&#xff1a; 向body内输出内容 注意&#xff1a; 如果输出的内容写的是标签&#xff0c;也会被解析成网页元素 语法2&#xff1a…

2023大同首届信息技术产业峰会举行,共话数字经济新未来

7月28日&#xff0c;“聚势而强共领信创”2023大同首届信息技术产业峰会圆满举行。本次峰会由中共大同市委、大同市人民政府主办&#xff0c;中国高科技产业化研究会国际交流合作中心、山西省信创协会协办&#xff0c;中共大同市云冈区委、大同市云冈区人民政府、诚迈科技&…

一文深入了解Cmk

目录 一、Cmk&#xff08;设备能力指数&#xff09;介绍&#xff1a;二、Cmk&#xff08;设备能力指数&#xff09; 概念&#xff1a;三、Cmk的应用时机&#xff1a;四、Cmk前期准备和要求&#xff1a;五、Cmk测试要求&#xff1a;六、CMK计算公式&#xff1a;七、Cmk实际操作&…

机器学习的关键词和算法总结

随着全球各行业的数据治理、数字化转型智能化辅助的引入发展&#xff0c;机器学习&#xff08;包括深度学习&#xff09;在逐步深入到各行各业&#xff0c;所以&#xff0c;有必要对机器学习的常见术语&#xff0c;经典算法及应用场景进行一次总结&#xff0c;其实机器学习兴起…

Vue2 第九节 过滤器

&#xff08;1&#xff09;定义&#xff1a;对要显示的数据进行特定格式化后再显示 &#xff08;2&#xff09;语法&#xff1a; ① 注册过滤器 1&#xff09;Vue.filter(name, callback) 全局过滤器 2&#xff09; new Vue({filters:{}}) 局部过滤器 ② 使用过滤器 1&…

SQL注入漏洞及解决(PreparedStatement对象)

四、SQL注入漏洞 加个or true都能查出来&#xff0c;很危险&#xff01;&#xff01;&#xff01; 会报错&#xff0c;因为代码中也拼了个引号 我们使用#将后面的内容注释起来&#xff0c;前面还是条完整的sql&#xff0c;还是能查到 使用—注释&#xff0c;代码可能加trim()&…

编译运行miniob最小数据库系统

minibo是一个用于教学的小型数据库系统&#xff0c;麻雀虽小五脏俱全&#xff0c;该项目包含了数据库的核心内容&#xff0c;并且代码量小&#xff0c;适合新手学习&#xff0c;最近由于需要学习c/cpp&#xff0c;因此打算从这个项目入手&#xff0c;本文就介绍编译运行miniob的…

《零基础入门学习Python》第072讲:GUI的终极选择:Tkinter9

这节课我们接着来讲解 Canvas 组件&#xff0c;既然 Cnavas 是画布的意思&#xff0c;那我们能不能让这个组件来设计一个画板呢&#xff1f;像Windows 自带的画图程序&#xff0c;我们的用户可以在上面随心所欲的绘制自己想要的图画&#xff0c;大家仔细想想&#xff0c;其实画…

美团小图币代挂教程

登陆美团官网获取对应的cookie 美团官网&#xff0c;点击右上角登陆对应账号。登陆成功后使用f12来获取 cookie 此时如果没有任何数据&#xff0c;点击网页刷新。找到如下的网络请求 赋值cookie项的全部内容&#xff0c;此时已经获取到对应账号的cookie 使用cookie登陆代挂…

NODEJS笔记

全局对象 global/window console.log/info/warn/error/time/timeEnd process.arch/platform/version/env/kill/pid/nextTick Buffer.alloc(5,abcde) String/toString setTimeout/clearTimeout setInterval/clearInterval setImmediate/clearImmediate process.nextTi…

1.netty介绍

1.介绍 是JBOSS通过的java开源框架是异步的,基于事件驱动(点击一个按钮调用某个函数)的网络应用框架,高性能高可靠的网络IO程序基于TCP,面向客户端高并发应用/点对点大量数据持续传输的应用是NIO框架 (IO的一层层封装) TCP/IP->javaIO和网络编程–>NIO—>Netty 2.应用…

HTTP请求走私漏洞简单分析

文章目录 HTTP请求走私漏洞的产生HTTP请求走私漏洞的分类HTTP请求走私攻击的危害确认HTTP请求走私漏洞通过时间延迟技术确认CL漏洞通过时间延迟技术寻找TE.CL漏洞 使用差异响应内容确认漏洞通过差异响应确认CL.TE漏洞通过差异响应确认TE.CL漏洞 请求走私漏洞的利用通过请求漏洞…

【面试题】与通义千问的芯片前端设计模拟面试归纳

这里是尼德兰的喵芯片设计相关文章,欢迎您的访问! 如果文章对您有所帮助,期待您的点赞收藏! 让我们一起为芯片前端全栈工程师而努力! 前言 两个小时,与chatGPT进行了一场数字IC前端设计岗的面试_尼德兰的喵的博客-CSDN博客 和GPT-3.5的回答可以对比品尝,味道更好。 模…

nacos源码打包及相关配置

nacos 本地下载后&#xff0c;需要 install 下&#xff1a; mvn clean install -Dmaven.test.skiptrue -Dcheckstyle.skiptrue -Dpmd.skiptrue -Drat.skiptruenacos源码修改后&#xff0c;重新打包生成压缩包命令&#xff1a;在 distribution 目录中运行&#xff1a; mvn -Pr…

数字化转型导师坚鹏:数字化时代扩大内需的8大具体建议

在日新月异的数字化时代、复杂多变的国际化环境下&#xff0c;扩大内需成为推动经济发展的国家战略&#xff0c;如何真正地扩大内需&#xff1f;结合本人15年的管理咨询经验及目前实际情况的深入研究&#xff0c;提出以下8大具体建议&#xff1a; 1、制定国民收入倍增计划。结…

QObject::connect: No such signal me::sendMsg(QString s) in ...

QObject::connect: No such signal me::sendMsg&#xff08;QString s&#xff09; in ... 解决方案 在使用qt4的connect中&#xff0c;爆的bug&#xff1a; 导致 teacher 的槽函数 receiveMsg(QString s) 一直没有被调用。。。。 解决方案 去掉参数名&#xff0c; 保留类型…