【C语言】使用C语言实现静态、动态的通讯录(简单易懂)

news2025/4/13 14:41:57

我们在学习结构体之后,就可以尝试去实现通讯录的制作,如果您这边对于结构体还没有太多的认识的话,请先访问这一篇文章,会有利于接下来的学习。【自定义类型】带你走进结构体、枚举、联合_小王学代码的博客-CSDN博客

 

目录

一、通讯录

二、静态通讯录

1.完成什么功能

2.通讯录的主干怎么写?

1.结构体的实现

2.初始化通讯录

3.添加人员

3.删除指定人员

4.查找指定人员的信息

5.改变指定人员的信息

6.打印通讯录人员信息

7.排序通讯录

三、动态通讯录

1.改动结构体

2.改动初始化

3.改动添加人员函数

四、整体通讯录代码

1.静态通讯录

1.test.c文件

2.Contact.c

3.Contact.h

2.动态通讯录

1.test.c

2.Contact.c

3.Contact.h

总结


前言

通讯录是一个简单的程序,我们接下来用C语言来实现静态以及动态通讯录。我们先了解一下什么叫静态?

静态通讯录:通讯录能存储人员的大小是固定的,可能会浪费,可能会不够

动态通讯录:可以实现动态扩容,不够就扩容,比较节省时间和空间,更加方便


一、通讯录

首先我们应该知道,通讯录应该有那些功能

1.增删查改,都要有

2.关闭通讯录

3.排序通讯录中的人员

二、静态通讯录

动态比静态只需要修改一部分内容,我们先讲解一下静态通讯录如何制作

1.完成什么功能

图示:

2.通讯录的主干怎么写?

使用菜单的形式,在main函数外使用test函数,在test中使用do while和switch函数,实现通讯录的基本框架,具体代码如下。

代码演示:


//这边进行主要的通讯录流程操作

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

}
void test() {
	int input = 0;
	int pos = 0;
	Contact pc;
	//Contact pc={0};
	//当然可以这样初始化,但是不一定后来初始化都这样,所以有InitContact()
	InitContact(&pc);
	do {
		menu();
	//打印选择菜单
		printf("请选择:>");
		scanf("%d", &input);
		switch (input) {
			case 1:
				addContact(&pc);
				break;
			case 2:
				delContact(&pc);
				break;
			case 3:
                searchContact(&pc);
				break;
			case 4:
				changeContact(&pc);
				break;
			case 5:
				showContact(&pc);
				break;
			case 6:
				sortContact(&pc);
				break;
			case 0:
				printf("退出通讯录\n");
				break;
			default:
				break;
			}
	} while (input);
}
int main()
{
	test();
	return 0;
}



3.逐步完成各项功能

初始化、增删改查,排序等功能的实现,我们放在Contact.c文件中进行实现

1.结构体的实现

代码如下:

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


//下面两个define是用于动态通讯录的
#define MAX1 3	//表示第一次容积是多少
#define MAX2 2  //表示一次扩容多少




//构建通讯录所需的结构体
typedef struct PeopleInfo {
	char name[NAME_MAX];//姓名
	int age;//年龄
	char sex[NAME_MAX];//性别
	char addr[ADDR_MAX];//地址
	char tele[TELE_MAX];//电话号码
}PeopleInfo;

//这是静态通讯录  就是data这个数组是固定死的MAX
typedef struct Contact {
	PeopleInfo data[MAX];//表示存储的通讯录最大人员数
	int sz;//表示当前Contact通讯录人员个数
}Contact;

2.初始化通讯录

代码如下:

//这是静态初始化
void InitContact(Contact* pc) {
	//进行初始化的时候,我们当然可以直接
	pc->sz = 0;
	memset(pc->data, 0, sizeof(pc->data));
	//memset 函数  这样的话,从data这个数组的地址开始 sizeof(pc->data)个字节,都赋值为0
}

使用了memset内存管理函数,对pc->data数组进行初始化都为0,sz表示的是人员个数,也为0

3.添加人员

代码如下:

//静态通讯录
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);
	printf("添加完成,请继续操作\n");
//添加完一个就sz++,表示有一个人员加入通讯录中
	pc->sz++;
}

3.删除指定人员

代码如下:

void delContact(Contact* pc) {
	assert(pc);
	printf("请选择删除的目标:>");
	if (pc->sz == 0) {
		return;
	}
	//删除的话只需要找到对应的要删除的数据,比如以名字为准,先找到,然后再讲其后面的元素覆盖前面的
	int pos = searchContact(pc);
	//换位置
	if (pos == -1) {
		printf("没有查找到该成员\n");
		return;
	}
	for (int i = pos; i < pc->sz - 1; i++) {
		pc->data[i] = pc->data[i + 1];
	}

	pc->sz--;//直接--不用管换位置之后最后一个数字的问题
	printf("删除完成\n");
}

可以删除指定姓名人员,当然可以自行做出一些改善,这是比较简单易懂的通讯录。

4.查找指定人员的信息

代码如下:

int  searchContact(Contact* pc) {
	assert(pc);//断言
	char name[20];
	int pos = -1; //pos等于-1是因为 如果找不到一样的姓名,就返回-1,表示没有
	scanf("%s", name);
	//查询
	for (int i = 0; i < pc->sz; i++) {
		if (strcmp(pc->data[i].name, name) == 0) {
			pos = i;   //使用strcmp函数,进行比较
		}
	}
	return pos;
}

使用了strcmp函数,大家有不理解的可以去下面链接进行访问查看

【C语言进阶】带你轻松玩转字符、字符串函数_小王学代码的博客-CSDN博客

5.改变指定人员的信息

代码如下:

int  searchContact(Contact* pc) {
	assert(pc);
	char name[20];
	int pos = -1;
	scanf("%s", name);
	//查询
	for (int i = 0; i < pc->sz; i++) {
		if (strcmp(pc->data[i].name, name) == 0) {
			pos = i;
		}
	}
	return pos;
}

//协助查找函数被,找到被查改人员在data数组的下标位置,再进行修改
void changeContact(Contact* pc) {
	assert(pc);
	//先找到
	int pos = searchContact(pc);
	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");
}

协助于查找函数,找到被查改人员在data数组的下标位置,再进行修改。

6.打印通讯录人员信息

代码如下:

void showContact(Contact* pc) {
	assert(pc);
	if (pc->sz == 0) {
		return;
	}//可以有可无
	printf("%-20s\t%-5s\t%-5s\t%-20s\t%-12s\n", "姓名", "年龄", "性别", "地址", "电话");
	for (int i = 0; i < pc->sz; i++) {
		printf("%-20s\t%-5d\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);
	}
	printf("打印完成\n");
}

对于printf中的 %-20s \ t 进行解释,-表示左对齐,20表示这个字符串20个位置,保持左对齐打印,\t 是字表符,是为了更加美观,使得各项数据对齐

7.排序通讯录

排序的依据有很多,我们这里是按照姓名大小排序,使用函数strcmp,实际上也可以使用qsort函数进行排序

代码如下:

void sortContact(Contact* pc) {
	assert(pc);
	if (pc->sz == 0) {
		printf("通讯录中暂无元素\n");
		return;
	}
	Contact s = { 0 };
	for (int i = 0; i < pc->sz-1; i++) {
		for (int j = i; j < pc->sz-1; j++) {
			if (strcmp(pc->data[j].name, pc->data[j + 1].name)==1) {
				s.data[j] = pc->data[j];
				pc->data[j] = pc->data[j + 1];
				pc->data[j + 1] = s.data[j];
			}
		}
	}
}

使用的是strcmp函数结合冒泡排序,这样还可以使用qsort函数,使用方法可以参考

【C语言进阶】指针的进阶(下)_小王学代码的博客-CSDN博客

qsort函数代码如下:

int compare(const void* e1, const void* e2) {
	return *((int*)e1) - *((int*)e2);
}
void sort(Contact*pc) {
	qsort(pc->data, pc->sz, sizeof(pc->data[0]), compare);
}

三、动态通讯录

动态通讯录相较于静态通讯录主要在结构体、初始化、增加成员的时候进行了改动

1.改动结构体

代码如下:

//构建通讯录所需的结构体
typedef struct PeopleInfo {
	char name[NAME_MAX];//姓名
	int age;//年龄
	char sex[NAME_MAX];//性别
	char addr[ADDR_MAX];//地址
	char tele[TELE_MAX];//电话号码
}PeopleInfo;
//实现动态通讯录
typedef struct Contact {
	PeopleInfo *data;//表示存储的通讯录最大人员数
	int sz;//表示当前Contact通讯录人员个数
	int capacity; //表示当前容量  作为扩容的依据
}Contact;

讲data数组变成指针的形式,不再固定通讯录容量大小,可以适当扩容

2.改动初始化

使用malloc函数进行内存申请,初始化

代码如下:

//这是动态通讯录的初始化
void InitContact(Contact* pc) {
	//进行初始化的时候,我们当然可以直接
	assert(pc);//断言
	pc->sz = 0;
	PeopleInfo *ptr=(PeopleInfo*)calloc(MAX1,sizeof(PeopleInfo));
	if (ptr == NULL) {
		perror("malloc::data");
		return;
	}
	pc->data = ptr;
	pc->capacity=MAX1;
}

对data空间进行申请,MAX1 表示的是初始的时候data容量大小

3.改动添加人员函数

实现扩容机制,如果sz和capacity相等,表示人员个数和容量相等,不能再添加人员了,这个时候需要check_capacity函数进行检查是否满,并扩容

代码如下:

//动态通讯录
void check_capacity(Contact* pc) {
	PeopleInfo* ptr = (PeopleInfo*)realloc(pc->data, sizeof(PeopleInfo)*(pc->capacity+MAX2));
	if (ptr == NULL) {
		perror("check_capacity");
		return;
	}
	pc->data = ptr;
	pc->capacity = pc->capacity + MAX2;
	
}
void addContact(Contact* pc) {
	assert(pc);
	if (pc->sz == pc->capacity) {
		//使用realloc函数 进行扩容
		check_capacity(pc);
		printf("扩容完成\n");
	}
	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);
	printf("添加完成,请继续操作\n");
	pc->sz++;
}

使用了realloc函数进行扩容处理

四、整体通讯录代码

1.静态通讯录

都有三种文件,test.c  Contact.c  Contact.h,分别是框架,实现,头文件声明,三个作用

1.test.c文件

#define _CRT_SECURE_NO_WARNINGS
#include"Contact.h"

//这边进行主要的通讯录流程操作

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

}
void test() {
	//打印选择菜单

	int input = 0;
	int pos = 0;
	Contact pc;
	//Contact pc={0};
	//当然可以这样初始化,但是不一定后来初始化都这样,所以有InitContact()
	InitContact(&pc);
	
	do {
		menu();
		printf("请选择:>");
		scanf("%d", &input);
		switch (input) {
			case 1:
				addContact(&pc);
				break;
			case 2:
				delContact(&pc);
				break;
			case 3:
				pos = searchContact(&pc);
				if (pos == -1) {
					printf("没有查找到该成员\n");
				}
				else {
					printf("%-20s\t%-5d\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);
				}
				break;
			case 4:
				changeContact(&pc);
				break;
			case 5:
				showContact(&pc);
				break;
			case 6:
				sort(&pc);
				break;
			case 0:
				printf("退出通讯录\n");
				break;
			default:
				break;
			}
	} while (input);
}
int main()
{
	test();
	return 0;
}

2.Contact.c

#define _CRT_SECURE_NO_WARNINGS
#include"Contact.h"
//用来实现头文件的代码
//
这是静态初始化
void InitContact(Contact* pc) {
	//进行初始化的时候,我们当然可以直接
	pc->sz = 0;
	memset(pc->data, 0, sizeof(pc->data));
	//memset 函数  这样的话,从data这个数组的地址开始 sizeof(pc->data)个字节,都赋值为0
}


静态通讯录
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);
	printf("添加完成,请继续操作\n");
	pc->sz++;
}

void delContact(Contact* pc) {
	assert(pc);
	printf("请选择删除的目标:>");
	if (pc->sz == 0) {
		return;
	}
	//删除的话只需要找到对应的要删除的数据,比如以名字为准,先找到,然后再讲其后面的元素覆盖前面的
	int pos = searchContact(pc);
	//换位置
	if (pos == -1) {
		printf("没有查找到该成员\n");
		return;
	}
	for (int i = pos; i < pc->sz - 1; i++) {
		pc->data[i] = pc->data[i + 1];
	}

	pc->sz--;//直接--不用管换位置之后最后一个数字的问题
	printf("删除完成\n");
}


int  searchContact(Contact* pc) {
	assert(pc);
	char name[20];
	int pos = -1;
	scanf("%s", name);
	//查询
	for (int i = 0; i < pc->sz; i++) {
		if (strcmp(pc->data[i].name, name) == 0) {
			pos = i;
		}
	}
	
	return pos;
}

void showContact(Contact* pc) {
	assert(pc);
	if (pc->sz == 0) {
		return;
	}//可以有可无
	printf("%-20s\t%-5s\t%-5s\t%-20s\t%-12s\n", "姓名", "年龄", "性别", "地址", "电话");
	for (int i = 0; i < pc->sz; i++) {
		printf("%-20s\t%-5d\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);
	}
	printf("打印完成\n");
}



void changeContact(Contact* pc) {
	assert(pc);
	//先找到
	int pos = searchContact(pc);
	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 sortContact(Contact* pc) {
	assert(pc);
	if (pc->sz == 0) {
		printf("通讯录中暂无元素\n");
		return;
	}
	Contact s;
	InitContact(&s);
	for (int i = 0; i < pc->sz-1; i++) {
		for (int j = 0; j < pc->sz-1-i; j++) {
			if (strcmp(pc->data[j].name, pc->data[j + 1].name)==1) {
				s.data[j] = pc->data[j];
				pc->data[j] = pc->data[j + 1];
				pc->data[j + 1] = s.data[j];
			}
		}
	}
}

int compare(const void* e1, const void* e2) {
	return *((int*)e1) - *((int*)e2);
}
void sort(Contact*pc) {
	qsort(pc->data, pc->sz, sizeof(pc->data[0]), compare);
}

3.Contact.h

#define _CRT_SECURE_NO_WARNINGS

//Contact 实现通讯录 头文件
#include<stdio.h>
#include<string.h>
#include<assert.h>
#include<malloc.h>
#include<stdlib.h>
#include<search.h>

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


//下面两个define是用于动态通讯录的
#define MAX1 3	//表示第一次容积是多少
#define MAX2 2  //表示一次扩容多少


//构建通讯录所需的结构体
typedef struct PeopleInfo {
	char name[NAME_MAX];//姓名
	int age;//年龄
	char sex[NAME_MAX];//性别
	char addr[ADDR_MAX];//地址
	char tele[TELE_MAX];//电话号码
}PeopleInfo;

//这是静态通讯录  就是data这个数组是固定死的MAX
typedef struct Contact {
	PeopleInfo data[MAX];//表示存储的通讯录最大人员数
	int sz;//表示当前Contact通讯录人员个数
}Contact;


//初始化通讯录
void InitContact(Contact* pc);
//添加通讯录的信息
void addContact(Contact* pc);
//删除通讯录中的信息
void delContact(Contact* pc);
//查找通讯录成员信息
int searchContact(Contact* pc);
//打印
void showContact(Contact* pc);
//改变指定元素
void changeContact(Contact* pc);
//排序,按照名字排序
void sortContact(Contact* pc);

2.动态通讯录

1.test.c

#define _CRT_SECURE_NO_WARNINGS
#include"Contact.h"

//这边进行主要的通讯录流程操作

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

}
void test() {
	//打印选择菜单

	int input = 0;
	int pos = 0;
	Contact pc;
	//Contact pc={0};
	//当然可以这样初始化,但是不一定后来初始化都这样,所以有InitContact()
	InitContact(&pc);
	
	do {
		menu();
		printf("请选择:>");
		scanf("%d", &input);
		switch (input) {
			case 1:
				addContact(&pc);
				break;
			case 2:
				delContact(&pc);
				break;
			case 3:
				pos = searchContact(&pc);
				if (pos == -1) {
					printf("没有查找到该成员\n");
				}
				else {
					printf("%-20s\t%-5d\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);
				}
				break;
			case 4:
				changeContact(&pc);
				break;
			case 5:
				showContact(&pc);
				break;
			case 6:
				sort(&pc);
				break;
			case 0:
				printf("退出通讯录\n");
                free(pc.data);
				break;
			default:
				break;
			}
	} while (input);
}
int main()
{
	test();
	return 0;
}

2.Contact.c

#define _CRT_SECURE_NO_WARNINGS
#include"Contact.h"
//用来实现头文件的代码
//


//这是动态通讯录的初始化
void InitContact(Contact* pc) {
	//进行初始化的时候,我们当然可以直接
	assert(pc);//断言
	pc->sz = 0;
	PeopleInfo *ptr=(PeopleInfo*)calloc(MAX1,sizeof(PeopleInfo));
	if (ptr == NULL) {
		perror("malloc::data");
		return;
	}
	pc->data = ptr;
	pc->capacity=MAX1;
}

//动态通讯录
void check_capacity(Contact* pc) {
	PeopleInfo* ptr = (PeopleInfo*)realloc(pc->data, sizeof(PeopleInfo)*(pc->capacity+MAX2));
	if (ptr == NULL) {
		perror("check_capacity");
		return;
	}
	pc->data = ptr;
	pc->capacity = pc->capacity + MAX2;
	
}
void addContact(Contact* pc) {
	assert(pc);
	if (pc->sz == pc->capacity) {
		//使用realloc函数 进行扩容
		check_capacity(pc);
		printf("扩容完成\n");
	}
	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);
	printf("添加完成,请继续操作\n");
	pc->sz++;
}
void delContact(Contact* pc) {
	assert(pc);
	printf("请选择删除的目标:>");
	if (pc->sz == 0) {
		return;
	}
	//删除的话只需要找到对应的要删除的数据,比如以名字为准,先找到,然后再讲其后面的元素覆盖前面的
	int pos = searchContact(pc);
	//换位置
	if (pos == -1) {
		printf("没有查找到该成员\n");
		return;
	}
	for (int i = pos; i < pc->sz - 1; i++) {
		pc->data[i] = pc->data[i + 1];
	}

	pc->sz--;//直接--不用管换位置之后最后一个数字的问题
	printf("删除完成\n");
}


int  searchContact(Contact* pc) {
	assert(pc);
	char name[20];
	int pos = -1;
	scanf("%s", name);
	//查询
	for (int i = 0; i < pc->sz; i++) {
		if (strcmp(pc->data[i].name, name) == 0) {
			pos = i;
		}
	}
	
	return pos;
}

void showContact(Contact* pc) {
	assert(pc);
	if (pc->sz == 0) {
		return;
	}//可以有可无
	printf("%-20s\t%-5s\t%-5s\t%-20s\t%-12s\n", "姓名", "年龄", "性别", "地址", "电话");
	for (int i = 0; i < pc->sz; i++) {
		printf("%-20s\t%-5d\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);
	}
	printf("打印完成\n");
}



void changeContact(Contact* pc) {
	assert(pc);
	//先找到
	int pos = searchContact(pc);
	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 sortContact(Contact* pc) {
	assert(pc);
	if (pc->sz == 0) {
		printf("通讯录中暂无元素\n");
		return;
	}
	Contact s;
	InitContact(&s);
	for (int i = 0; i < pc->sz-1; i++) {
		for (int j = 0; j < pc->sz-1-i; j++) {
			if (strcmp(pc->data[j].name, pc->data[j + 1].name)==1) {
				s.data[j] = pc->data[j];
				pc->data[j] = pc->data[j + 1];
				pc->data[j + 1] = s.data[j];
			}
		}
	}
}

int compare(const void* e1, const void* e2) {
	return *((int*)e1) - *((int*)e2);
}
void sort(Contact*pc) {
	qsort(pc->data, pc->sz, sizeof(pc->data[0]), compare);
}

3.Contact.h

#define _CRT_SECURE_NO_WARNINGS

//Contact 实现通讯录 头文件
#include<stdio.h>
#include<string.h>
#include<assert.h>
#include<malloc.h>
#include<stdlib.h>
#include<search.h>

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


//下面两个define是用于动态通讯录的
#define MAX1 3	//表示第一次容积是多少
#define MAX2 2  //表示一次扩容多少

//构建通讯录所需的结构体
typedef struct PeopleInfo {
	char name[NAME_MAX];//姓名
	int age;//年龄
	char sex[NAME_MAX];//性别
	char addr[ADDR_MAX];//地址
	char tele[TELE_MAX];//电话号码
}PeopleInfo;

//实现动态通讯录
typedef struct Contact {
	PeopleInfo *data;//表示存储的通讯录最大人员数
	int sz;//表示当前Contact通讯录人员个数
	int capacity; //表示当前容量  作为扩容的依据
}Contact;

//初始化通讯录
void InitContact(Contact* pc);
//添加通讯录的信息
void addContact(Contact* pc);
//删除通讯录中的信息
void delContact(Contact* pc);
//查找通讯录成员信息
int searchContact(Contact* pc);
//打印
void showContact(Contact* pc);
//改变指定元素
void changeContact(Contact* pc);
//排序,按照名字排序
void sortContact(Contact* pc);

总结

静态通讯录和动态通讯录都是比较简单好实现的,静态通讯录是固定的数组的形式储存成员,不确定成员个数的情况下,可能会浪费空间,也可能不够用。但是动态通讯录通过不断扩容,更好的解决了这个空间的事情,不会造成太多浪费。

动态,是依靠malloc、free、calloc、realloc这些函数进行申请空间,进行维护不断扩容的,下一章节,我们来一起细致的去讲解一下这四种函数的使用和区别

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

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

相关文章

JVM-【面试题】-对象内存分配

一、对象内存分配流程图如果能在栈分布就直接在栈创建如果是大对象就直接在old区创建如果不大于TLAB则在TLAB创建&#xff0c;否则在Eden区创建如果Eden区空间不足就会发生Minor GC进行回收&#xff0c;回收的空间放不下或年龄达到上限就直接放到Old区&#xff0c;之后S0区的存…

Vue3.0 性能提升主要是通过哪几方面体现的?

一、编译阶段 回顾Vue2&#xff0c;每个组件实例都对应一个 watcher 实例&#xff0c;它会在组件渲染的过程中把用到的数据property记录为依赖&#xff0c;当依赖发生改变&#xff0c;触发setter&#xff0c;则会通知watcher&#xff0c;从而使关联的组件重新渲染 试想一下&…

34420A万用表

18320918653 34420A Agilent 34420A 七位半台式数字万用表|安捷伦纳伏表34420A|微欧表|安捷伦34420A 品牌&#xff1a; Agilent(安捷伦) 1.3nV rms噪声/8n Vp-p 100pV&#xff0c;100nΩ灵敏度 两通道可编程电压输入&#xff1a;差分和比值功能 71/2位分辨率 1mV到100V量程…

如何通过指令控制将一副扑克牌变成一种简单的计算机

题目 题目就是文章的标题 已知 牌数&#xff1a;每套扑克牌有54张&#xff0c;其中去掉大小王&#xff0c;剩下52张&#xff0c;这52张中又有4种花色黑桃&#xff0c;红桃&#xff0c;梅花&#xff0c;方片每种花色都有13张&#xff08;1,2,3,4,5,6,7,8,9,10,J,Q,K&#xff…

【Ubuntu】在VMWare虚拟机中安装Ubuntu【教程】

文章目录【Ubuntu】在VMWare虚拟机中安装Ubuntu教程一、安装VMWare二、下载Ubuntu的iso文件三、安装UbuntuReference【Ubuntu】在VMWare虚拟机中安装Ubuntu教程 一、安装VMWare 具体的安装方法&#xff0c;可以参考这一篇博客&#xff0c;这里就不详细介绍了 二、下载Ubuntu…

centos禁止root登录

ssh登录linux服务器的时候&#xff0c;经常会有提示 There were * failed login attempts since the last successful login. 说明有大量的非法登录尝试 检查服务器是否被恶意登录 # Ubuntu # 1. 查看近期成功的密码登录&#xff1a; grep "password" /var/log/au…

如何搭建邮箱服务器?mail系统架设的两种方法

邮件mail通信是常用的办公场景&#xff0c;对于技术和网管等人员&#xff0c;往往需要搭建自己的邮箱服务器。那么&#xff0c;如何架设邮箱系统呢&#xff1f;通常有两种方案&#xff0c;一种是在在本地主机部署&#xff0c;另一种是在云端如云服务器上部署应用。根据主机IP情…

以交互方式导入图像、音频和视频

以交互方式将数据导入到 MATLAB 工作区。 查看文件的内容 指定变量 生成可重用的 MATLAB 代码 注意&#xff1a;​有关导入文本文件的信息&#xff0c;可以参考使用导入工具读取文本文件数据。有关导入电子表格的信息&#xff0c;可以参考使用导入工具读取电子表格数据。 查…

【Redis数据对象与结构】string与其底层结构

【Redis数据对象与结构】string与其底层结构 【Redis数据对象与结构】系列的主线如下&#xff0c;本文主要讲解string数据对象及其底层结构在redis中的实现。 redis中基本的数据对象有字符串类型(String)、列表类型(List)、字典类型(Hash)、集合类型(Set)、有序列表类型(Sorte…

自定义类型之枚举与联合

文章目录前言一、枚举1.枚举的定义2.枚举的几种情况3.枚举类型的大小4.枚举的优点二、联合&#xff08;共用体&#xff09;1.联合类型的定义2.联合的特点3.联合的大小计算总结前言 自定义类型很多人可能只知道结构体&#xff0c;因为结构体相对来说确实用的比较多&#xff0c;而…

爬虫攻守道 - 2023最新 - 正则表达式勇猛精进 - 爬取某天气网站历史数据

前言 在 正则表达式 - 匹配开头、结尾、中间 - 某天气网站网页源代码分析 这篇文章里&#xff0c;我们介绍了如何用正则表达式匹配包含特定样式的Table标签&#xff0c;也就是同时匹配开头、结尾、以及中间。 当你能真正理解这个写法&#xff0c;就会觉得不过是柳暗花明罢了。…

如何把拍摄视频中多余的人或物去除?

大家应该都有这样一个烦恼吧&#xff1f;就是拍摄的一段视频中有多余的人物出现&#xff0c;想要把里面的人物去除掉&#xff0c;或者是自己拍摄的一段视频&#xff0c;视频里出现了多余的人物&#xff0c;但是又不能重启拍摄的情况下&#xff0c;想要把视频中的人物去除掉应该…

Spring Security笔记

创建个项目 引入Spring Web和Spring Security 即可 写个Controller接收请求 转发重定向都可以 static下定义两个页面 login.html页面 用来登录 main.html如果可以跳到这里,说明登录成功 启动运行程序 我们访问登录接口 或者是访问静态资源都会重定向到这个页面 这个页面说…

并发编程(多线程)

一、进程与线程 多进程编程已经能够解决并发编程的问题了(已经可以利用cpu多核资源了).但是仍然存在这缺陷. 就是,进程太重了(消耗资源多,速度慢),线程应运而生被称为"轻量级编程",解决并发编程的各种问题的同时,让IO速度大大提升. 线程"轻"主要"轻…

SOFAEnclave:蚂蚁金服新一代可信编程环境,让机密计算为金融业务保驾护航102年

引言 互联网金融本质上是对大量敏感数据的处理以及由此沉淀的关键业务智能。近年来涌现出来的新业态更是将数据处理的范畴从单方数据扩展到了涉及合作方的多方数据。 另一方面&#xff0c;从 GDPR 到 HIPAA&#xff0c;数据隐私监管保护的范围愈加扩大&#xff0c;力度日益增…

app逆向 || x动

声明 本文仅供学习参考&#xff0c;如有侵权可私信本人删除&#xff0c;请勿用于其他途径&#xff0c;违者后果自负&#xff01; 如果觉得文章对你有所帮助&#xff0c;可以给博主点击关注和收藏哦&#xff01; 本文适用于对安卓开发和Java有了解的同学! 文中涉及的app均放在…

运行Dlinknet提取道路和水体(总结帖)——全流程步骤总结

之前写了很多制作样本然后跑代码的帖子 但由于我也是第一次跑 记录一下自己摸索的过程 因此导致 每一篇的内容很碎 每次我想自己去回顾一下的时候 都有太多摸索尝试的过程了 因此我在这里总结一下我摸索的整个过程的详细步骤 大家可以先看这篇再去我的对应博客里面看具体的细节…

【C++逆向】虚表(Virtual table)

什么是多态 定义一个虚基类ISpeaker class ISpeaker{ protected:size_t b; public:ISpeaker( size_t _v ): b(_v) {}virtual void speak() 0; };有两个子类&#xff0c;都实现了虚函数speak()&#xff1a; class Dog : public ISpeaker { public:Dog(): ISpeaker(0){}//vir…

Gin操作MySQLd的增加修改删除的Restful风格的API

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文 目录 一、gin是什么? 二、gin- mysql 1.gin-mysql 2.CRUD的gin的mysql 通过jsontool

Win10忘记开机密码无法进入桌面怎么办?

Win10忘记开机密码无法进入桌面怎么办&#xff1f;有用户设置了电脑的开机密码之后&#xff0c;因为一段时间没有去开机使用电脑了&#xff0c;导致将开机的密码忘记了。那么这个情况下我们怎么去进行电脑的开机呢&#xff1f;接下来我们来看看详细的解决方法分享吧。 解决方法…