【C版本】静态通讯录与动态通讯录的实现,以及各自所存在的缺陷对比。(含所有原码)

news2025/7/9 5:57:09

通讯录


目录

  • 静态版本通讯录
    • 前期思路
    • 具体实现
      • 1、框架
      • 2、初始化通讯录
      • 3、增加联系人
      • 4、显示已有联系人
      • 5、查找联系人
      • 6、删除指定联系人
      • 7、排序联系人
      • 8、修改联系人信息
      • 9、清空联系人
    • 静态版本通讯录存在的缺陷
  • 动态版本通讯录(静态版本的部分功能发生改动)
      • 初始化
      • 增加联系人
      • 退出程序(释放空间)
    • 动态版本通讯录存在的缺陷
  • 动态通讯录原码

静态版本通讯录

前期思路

与之前的扫雷以及三子棋的实现方式是一样的,创建两个源文件,一个用来测试,一个用来存放函数定义,再创建一个头文件,用来存放函数声明。接下来是着手实现通讯录。
首先要有一个大概的框架,并且要明确即将实现的通讯录的功能,最基本的即增删查改,然后对这些功能进行进一步的细化实现,并且我们知道,人的信息是一个比较复杂的对象,不可能用一句话就概括,所以就用到了之前学过的结构体,一个结构体用来存放联系人,另一个用来存放联系人对应的的基本信息。
最后我们要知道一点,就是一口吃不成一个大胖子,功能实现的过程是一步步来的。

在这里插入图片描述

具体实现

1、框架

首先创建一个用来存放联系人以及记录联系人个数的结构体,然后把联系人的信息也存放在这个结构体中,如下:

//联系人信息
struct message
{
	//姓名
	char name[NAME];
	//性别
	char sex[SEX];
	//电话
	char tele[TELE];
	//住址
	char addr[ADDR];
	//年龄
	int age;
};
//通讯录
struct contact
{
	//存放联系人的数组,数组里存放的元素类型是结构体类型,即存放联系人的信息。
	struct message data[MAX];
	//记录联系人的个数
	int sz;
};

这里我们可以用define来定义一个常量,这样后续修改起来也比较容易,不要把程序写死。

#define NAME 20//姓名
#define SEX 5//性别
#define TELE 12//电话
#define ADDR 30//住址
#define MAX 100//联系人最大个数

然后在.c的测试文件里书写菜单栏。

(个人建议:像这种,不算是特别复杂的对象,就可以提前制定一个框架,也就是菜单栏,但是后面学到数据结构的时候,建议最后再添加,因为菜单栏的存在,会使一些调试比较麻烦。)

一个基本的框架,满足上面提到的一些功能,实现起来也比较容易,用一个简单的do while即可,如下:

#include"contact_.h"
//菜单栏
void menu()
{
	printf("--------------------------------------------------------------\n");
	printf("---------   1、增加联系人       2、删除指定联系人    ---------\n");
	printf("---------   3、修改联系人信息   4、查找联系人        ---------\n");
	printf("---------   5、排序联系人       6、显示已有联系人    ---------\n");
	printf("---------   0、退出             7、清空联系人        ---------\n");
	printf("--------------------------------------------------------------\n");
}

int main()
{
	int input = 0;
	//创建通讯录
	struct contact con;
	//初始化通讯录
	Init_contact(&con);
	do
	{
		menu();
		printf("请选择:->");
		scanf("%d", &input);
		system("cls");
		switch (input)
		{
		case 1:
			//增加联系人
			Add_contact(&con);
			break;
		case 2:
			//删除联系人
			Show_contact(&con);
			Dele_contact(&con);
			break;
		case 3:
			//修改联系人信息
			Show_contact(&con);
			revise_contact(&con);
			break;
		case 4:
			//查找联系人信息
			Find_contact(&con);
			break;
		case 5:
			//排序联系人信息
			Show_contact(&con);
			Sort_contact(&con);
			break;
		case 6:
			//显示联系人
			system("cls");
			Show_contact(&con);
			printf("\n");
			break;
		case 7:
			//清空联系人
			Clear(&con);
			break;
		case 0:
			break;
		default:
			printf("输入错误!\n");
			break;
		}

	} while (input);
	return 0;
}

2、初始化通讯录

与扫雷游戏一样,首先先把通讯录初始化,然后再存放信息。实现起来也很简单。

//初始化通讯录
void Init_contact(struct contact* p)
{
	assert(p);
	p->sz = 0;//sz是记录联系人个数的变量
	memset(p->data, 0, MAX * sizeof(struct message));
	//p指向的data数组(存放联系人的)里,把MAX个联系人信息都置为0
	//memset是一个内存函数,修改存储在内存的数据
}

3、增加联系人

增加一个联系人,即增加姓名、性别、电话等信息,把这些信息输入在结构体数组中对应得结构体成员即可,如下:

//增加联系人
void Add_contact(struct contact* p)
{
	assert(p);
	if (p->sz == MAX)
		printf("联系人已满!!!\n");
	printf("请输入姓名:->");
	scanf("%s", p->data[p->sz].name);
	printf("请输入性别:->");
	scanf("%s", p->data[p->sz].sex);
	printf("请输入电话:->");
	scanf("%s", p->data[p->sz].tele);
	printf("请输入住址:->");
	scanf("%s", p->data[p->sz].addr);
	printf("请输入年龄:->");
	scanf("%d", &(p->data[p->sz].age));
	system("cls");
	//清屏
	printf("增加成功!\n");
	printf("\n");
	p->sz++;//每增加一个,sz也跟着++
}

在这里插入图片描述
说白了这块知识点就是结构体成员的访问,只不过这里访问了两次

4、显示已有联系人

//显示联系人
void Show_contact(const struct contact* p)
{
	assert(p);
	int i = 0;
	//为了显示出来更加有美感,先打印一行基本信息
	printf("%-20s\t%-5s\t%-12s\t%-20s\t%-5s\n", "姓名", "性别", "电话", "住址", "年龄");
	//循环打印即可,sz记录目前联系人个数
	for (i = 0; i < p->sz; i++)
	{
	     // 一一对应即可
		printf("%-20s\t%-5s\t%-12s\t%-20s\t%-5d\n", p->data[i].name,
			p->data[i].sex,
			p->data[i].tele,
			p->data[i].addr,
			p->data[i].age);
	}
}

实现完成如下;
在这里插入图片描述

5、查找联系人

查找联系人的实现也很简单,定义一个函数,遍历整个data数组,如果不存在返回-1,打印不存在,存在就返回1,打印该联系人信息。如下:

//这里遍历整个数组,如果不存在,则返回-1,存在返回1
int find_name(const struct contact* p, char arr[])
{
	assert(p);
	int i = 0;
	for (i = 0; i < p->sz; i++)
	{
		if (0 == strcmp(p->data[i].name, arr))
			return i;
	}
	return -1;
}
//查找联系人信息
void Find_contact(const struct contact* p)
{
	assert(p);
	char del_name[NAME];
	printf("请输入要查找联系人的姓名:->");
	scanf("%s", del_name);
	system("cls");

	//查找该联系人
	int ret = find_name(p, del_name);
	if (ret == -1)
		printf("查无此人!\n");
	//返回值为1,打印出该联系人信息即可
	else
	{
		printf("%-20s\t%-5s\t%-12s\t%-20s\t%-5s\n", "姓名", "性别", "电话", "住址", "年龄");
		printf("%-20s\t%-5s\t%-12s\t%-20s\t%-5d\n", p->data[ret].name,
			p->data[ret].sex,
			p->data[ret].tele,
			p->data[ret].addr,
			p->data[ret].age);
	}
}

6、删除指定联系人

实现删除的功能也很简单,由于数组在内存中是连续存放的,只需要后面的覆盖即可,原理如下:
在这里插入图片描述
具体用代码实现如下:

//删除联系人
void Dele_contact(struct contact* p)
{
	assert(p);
	char del_name[NAME];
	printf("请输入要删除联系人的姓名:->");
	scanf("%s", del_name);
	//查找该联系人
	int ret = find_name(p, del_name);
	if (ret == -1)
		printf("查无此人!\n");
	else
	{
		int j = 0;
		for (j = ret; j < p->sz - 1; j++)
		{
			p->data[j] = p->data[j + 1];//后面的覆盖前面的
		}
		p->sz--;
		system("cls");

		printf("删除成功!\n");
		printf("\n");
	}
}

7、排序联系人

这里我又新增了一步,就是可以实现按姓名、住址、年龄、性别排序,用qsort即可实现,不懂的可以去翻看我前面的指针进阶文章,里面有介绍。具体实现如下:

//排序菜单
void menu_sort()
{
	printf("******   1、姓名   ******\n");
	printf("******   2、住址   ******\n");
	printf("******   3、年龄   ******\n");
	printf("******   4、性别   ******\n");
	printf("******   0、退出   ******\n");
}

//姓名排序
int cmp_name(const void* e1, const void* e2)
{
	return strcmp(((struct message*)e1)->name, ((struct message*)e2)->name);
}
//住址排序
int cmp_addr(const void* e1, const void* e2)
{
	return strcmp(((struct message*)e1)->addr, ((struct message*)e2)->addr);
}
//年龄排序
int cmp_age(const void* e1, const void* e2)
{
	return ((struct message*)e1)->age - ((struct message*)e2)->age;
}
//性别排序
int cmp_sex(const void* e1, const void* e2)
{
	return strcmp(((struct message*)e1)->sex, ((struct message*)e2)->sex);
}
//排序联系人
void Sort_contact(struct contact* p)
{
	int s = 0;
	do
	{
		//排序菜单
		menu_sort();
		printf("请选择排序类型:->");
		scanf("%d", &s);
		system("cls");
		switch (s)
		{
		case 1:
			qsort(p->data, p->sz, sizeof(struct message), cmp_name);
			printf("排序成功!\n");
			break;
		case 2:
			qsort(p->data, p->sz, sizeof(struct message), cmp_addr);
			printf("排序成功!\n");
			break;
		case 3:
			qsort(p->data, p->sz, sizeof(struct message), cmp_age);
			printf("排序成功!\n");
			break;
		case 4:
			qsort(p->data, p->sz, sizeof(struct message), cmp_sex);
			printf("排序成功!\n");
			break;
		case 0:
			printf("退出排序\n");
			break;
		default:
			printf("输入有误!\n");
			break;
		}

	} while (s);
}

8、修改联系人信息

修改联系人信息,首先找到这个联系人,然后再进行修改,这里我是可以把信息有选择性的修改,实现起来也很简单

//修改菜单栏
void menu_()
{
	printf("***********************************\n");
	printf("******   1、修改联系人姓名   ******\n");
	printf("******   2、修改联系人电话   ******\n");
	printf("******   3、修改联系人年龄   ******\n");
	printf("******   4、修改联系人住址   ******\n");
	printf("******   5、修改联系人性别   ******\n");
	printf("******   0、返回主菜单       ******\n");

}
//修改联系人信息
void revise_contact(struct contact* p)
{
	assert(p);
	char del_name[NAME];
	printf("请输入要修改信息的联系人的姓名:->");
	scanf("%s", del_name);
	int ret = find_name(p, del_name);
	if (ret == -1)
	{
		printf("查无此人!\n");
		printf("\n");
	}
	else
	{
		int in_put = 0;
		do
		{
			menu_();
			scanf("%d", &in_put);
			switch (in_put)
			{
			case 1:
				printf("请输入修改后的姓名:->");
				scanf("%s", p->data[ret].name);
				system("cls");

				printf("姓名修改成功!\n");
				break;
			case 2:
				printf("请输入修改后的电话:->");
				scanf("%s", p->data[ret].tele);
				system("cls");

				printf("电话修改成功!\n");
				break;
			case 3:
				printf("请输入修改后的年龄:->");
				scanf("%d", &(p->data[ret].age));
				system("cls");

				printf("年龄修改成功!\n");
				break;
			case 4:
				printf("请输入修改后的住址:->");
				scanf("%s", p->data[ret].addr);
				system("cls");

				printf("住址修改成功!\n");
				break;
			case 5:
				printf("请输入修改后的性别:->");
				scanf("%s", p->data[ret].sex);
				system("cls");

				printf("性别修改成功!\n");
				break;
			case 0:
				printf("取消修改!\n");
				break;
			default:
				printf("输入错误!\n");
				break;
			}
		} while (in_put);
	}
}

9、清空联系人

这一步是最容易实现的一步,只需要置空sz即可,到这里也算是苦尽甘来。

//清空联系人
void Clear(struct contact* p)
{
	p->sz = 0;
	printf("清空成功!\n");
}

至此。一个功能齐全的通讯录实现完毕。

静态版本通讯录存在的缺陷

我们看到,上面的版本我们定义了数组大小为100,也就是能存放100人的信息,data空间是已经开辟了的,假如我们要存放第101个人的信息呢?这不就存不下了,有的铁子可能说,那我们可以定义为1000呀,你总不能有这么多联系人用来存放吧。
确实如此,但是后面的空间不就浪费了。那有什么办法可以实现按照我们的需求来开辟合适的空间呢?答案是有的,就是后面的动态内存版本。


动态版本通讯录(静态版本的部分功能发生改动)

动态版本的通讯录是在静态版本上进行的一次优化,即实现按照需求开辟空间。和之前版本有所不同,不用一个结构体数组来存放联系人,而是用了一个结构体指针。如下:

#define NAME 20
#define SEX 5
#define TELE 12
#define ADDR 30

#define DEFAULT_SZ 3//初始容量
#define INC_SZ 2//扩容
//联系人信息
struct message
{
	//姓名
	char name[NAME];
	//性别
	char sex[SEX];
	//电话
	char tele[TELE];
	//住址
	char addr[ADDR];
	//年龄
	int age;
};
//通讯录
struct contact
{
	struct message* data;//结构体指针
	int sz;//个数
	int capacity;//通讯录容量
};

由于是动态版本的,所以在初始化、增加联系人、以及最后的退出里,有了一定的修改,别的只要不涉及增加空间的操作,都与静态版本相同。这里就不一一再写了。

初始化

//初始化通讯录
void Init_contact(struct contact* p)
{
	assert(p);
	//开辟空间
	p->data =(struct message*) malloc(DEFAULT_SZ * sizeof(struct message));
	//假如开辟失败,报错
	if (p->data == NULL)
	{
		printf("%s\n", strerror(errno));
		return;
	}
	p->sz = 0;
	p->capacity = DEFAULT_SZ;

}

这里的capacity是当前通讯录的容量,sz是记录当前联系人的数量,当数量==容量时,就要进行扩容。
所以这里又增加了一个用来判断是否扩容的函数,这个函数算是动态版本通讯录的核心函数了

//是否判断增容
int check_capacity(struct contact*p)
{
	//当联系人个数 == 通讯录容量时,增容INC_SZ个内存空间
	if (p->sz == p->capacity)
	{
		struct message* ptr = (struct message*)realloc(p->data, (p->capacity + INC_SZ) * sizeof(struct message));
		if (ptr == NULL)//判断是否增容失败
		{
			printf("%s\n", strerror(errno));
			return 0;
		}
		else
		{
			p->data = ptr;//增容成功,data就指向这块新开辟的空间
			p->capacity += INC_SZ;//容量+=INC_SZ
			//printf("增容成功!\n");
			return 1;
		}
	}
	//不需要增容
	else
		return 1;
}

增加联系人

这里的增加联系人,就要在增加之前进行判断,空间是否需要扩容,如下:
check_capacity时上面写的用来判断知否增容的函数。

//增加联系人
void Add_contact(struct contact* p)
{
	assert(p);
	if (0 == check_capacity(p))
	{
		printf("%s\n", strerror(errno));
		return;
	}
	printf("请输入姓名:->");
	scanf("%s", p->data[p->sz].name);

	printf("请输入性别:->");
	scanf("%s", p->data[p->sz].sex);

	printf("请输入电话:->");
	scanf("%s", p->data[p->sz].tele);

	printf("请输入住址:->");
	scanf("%s", p->data[p->sz].addr);

	printf("请输入年龄:->");
	scanf("%d", &(p->data[p->sz].age));
	system("cls");

	printf("增加成功!\n");
	printf("\n");
	p->sz++;
}

退出程序(释放空间)

malloc这些动态内存管理函数,都是与free成对出现的,这里的释放空间就是需要在程序退出的时候,进行释放,否则造成内存泄漏问题。这里free后置空即可。

//释放空间
void Destory_contact(struct contact* p)
{
	free(p->data);
	p->data=NULL;
	p->sz = 0;
	p->capacity = 0;
}


至此,动态版本通讯录实现完毕,就是在静态版本的基础上进行了修改,主要涉及到了增容问题,处理好即可。

动态版本通讯录存在的缺陷

唯一的缺陷就在于不能把信息保存下来,也就是说,当下次打开程序的时候,上一次写的都没了,也就是说,这是一个“一次性”的通讯录。当然,后面还会有进一步的改动,实现真正意义上的通讯录,即可以把每次的信息保存下来,后续会书写。

动态通讯录原码

头文件

#pragma once
#include<stdio.h>
#include<string.h>
#include<assert.h>
#include<stdlib.h>
#include<Windows.h>
#include<errno.h>

#define NAME 20
#define SEX 5
#define TELE 12
#define ADDR 30

#define DEFAULT_SZ 3//初始容量
#define INC_SZ 2//扩容

//联系人信息
struct message
{
	//姓名
	char name[NAME];
	//性别
	char sex[SEX];
	//电话
	char tele[TELE];
	//住址
	char addr[ADDR];
	//年龄
	int age;
};
//通讯录
struct contact
{
	struct message* data;
	int sz;//个数
	int capacity;//通讯录容量
};
//初始化通讯录
void Init_contact(struct contact* p);
//动态增加联系人
void Add_contact(struct contact* p);
//显示联系人
void Show_contact(const struct contact* p);
//删除联系人
void Dele_contact(struct contact* p);
//修改联系人信息
void revise_contact(struct contact* p);
//查找联系人信息
void Find_contact(const struct contact* p);
//排序联系人
void Sort_contact(struct contact* p);
//清空联系人
void Clean(struct contact* p);
//释放空间
void Destory_contact(struct contact* p);

.c测试源文件

#define _CRT_SECURE_NO_WARNINGS 1
#include"contact_dynamic.h"

void menu()
{
	printf("--------------------------------------------------------------\n");
	printf("---------   1、增加联系人       2、删除指定联系人    ---------\n");
	printf("---------   3、修改联系人信息   4、查找联系人        ---------\n");
	printf("---------   5、排序联系人       6、显示已有联系人    ---------\n");
	printf("---------   0、退出             7、清空联系人        ---------\n");
	printf("--------------------------------------------------------------\n");
}

int main()
{
	int input = 0;
	//创建通讯录
	struct contact con;
	//初始化通讯录
	Init_contact(&con);
	do
	{
		menu();
		printf("请选择:->");
		scanf("%d", &input);
		system("cls");
		switch (input)
		{
		case 1:
			//增加联系人
			Add_contact(&con);
			break;
		case 2:
			//删除联系人
			Show_contact(&con);
			Dele_contact(&con);
			break;
		case 3:
			//修改联系人信息
			Show_contact(&con);
			revise_contact(&con);
			break;
		case 4:
			//查找联系人信息
			Find_contact(&con);
			break;
		case 5:
			//排序联系人信息
			Show_contact(&con);
			Sort_contact(&con);
			break;
		case 6:
			//显示联系人
			system("cls");
			Show_contact(&con);
			printf("\n");
			break;
		case 7:
			//清空联系人
			Clean(&con);
			break;
		case 0:
			//释放空间
			Destory_contact(&con);
			break;
		default:
			printf("输入错误!\n");
			break;
		}
	} while (input);
	return 0;
}

.c存放函数定义的源文件

#include"contact_dynamic.h"

//初始化通讯录
void Init_contact(struct contact* p)
{
	assert(p);
	//开辟空间
	p->data =(struct message*) malloc(DEFAULT_SZ * sizeof(struct message));
	//假如开辟失败,报错
	if (p->data == NULL)
	{
		printf("%s\n", strerror(errno));
		return;
	}
	p->sz = 0;
	p->capacity = DEFAULT_SZ;

}
//是否判断增容
int check_capacity(struct contact*p)
{
	//当联系人个数 == 通讯录容量时,增容INC_SZ个内存空间
	if (p->sz == p->capacity)
	{
		struct message* ptr = (struct message*)realloc(p->data, (p->capacity + INC_SZ) * sizeof(struct message));
		if (ptr == NULL)//判断是否增容失败
		{
			printf("%s\n", strerror(errno));
			return 0;
		}
		else
		{
			p->data = ptr;//增容成功,data就指向这块新开辟的空间
			p->capacity += INC_SZ;//容量+=INC_SZ
			//printf("增容成功!\n");
			return 1;
		}
	}
	//不需要增容
	else
		return 1;
}

//增加联系人
void Add_contact(struct contact* p)
{
	assert(p);
	if (0 == check_capacity(p))
	{
		printf("%s\n", strerror(errno));
		return;
	}
	printf("请输入姓名:->");
	scanf("%s", p->data[p->sz].name);

	printf("请输入性别:->");
	scanf("%s", p->data[p->sz].sex);

	printf("请输入电话:->");
	scanf("%s", p->data[p->sz].tele);

	printf("请输入住址:->");
	scanf("%s", p->data[p->sz].addr);

	printf("请输入年龄:->");
	scanf("%d", &(p->data[p->sz].age));
	system("cls");

	printf("增加成功!\n");
	printf("\n");
	p->sz++;
}
//显示联系人
void Show_contact(const struct contact* p)
{
	assert(p);
	int i = 0;
	printf("%-20s\t%-5s\t%-12s\t%-20s\t%-5s\n", "姓名", "性别", "电话", "住址", "年龄");
	for (i = 0; i < p->sz; i++)
	{
		printf("%-20s\t%-5s\t%-12s\t%-20s\t%-5d\n", p->data[i].name,
			p->data[i].sex,
			p->data[i].tele,
			p->data[i].addr,
			p->data[i].age);
	}
}
int find_name(const struct contact* p, char arr[])
{
	assert(p);
	int i = 0;
	for (i = 0; i < p->sz; i++)
	{
		if (0 == strcmp(p->data[i].name, arr))
			return i;
	}
	return -1;
}
//删除联系人
void Dele_contact(struct contact* p)
{
	assert(p);
	char del_name[NAME];
	printf("请输入要删除联系人的姓名:->");
	scanf("%s", del_name);
	//查找该联系人
	int ret = find_name(p, del_name);
	if (ret == -1)
		printf("查无此人!\n");
	else
	{
		int j = 0;
		for (j = ret; j < p->sz - 1; j++)
		{
			p->data[j] = p->data[j + 1];
		}
		p->sz--;
		system("cls");

		printf("删除成功!\n");
		printf("\n");
	}
}
//修改菜单栏
void menu_()
{
	printf("***********************************\n");
	printf("******   1、修改联系人姓名   ******\n");
	printf("******   2、修改联系人电话   ******\n");
	printf("******   3、修改联系人年龄   ******\n");
	printf("******   4、修改联系人住址   ******\n");
	printf("******   5、修改联系人性别   ******\n");
	printf("******   0、返回主菜单       ******\n");

}
//修改联系人信息
void revise_contact(struct contact* p)
{
	assert(p);
	char del_name[NAME];
	printf("请输入要修改信息的联系人的姓名:->");
	scanf("%s", del_name);
	int ret = find_name(p, del_name);
	if (ret == -1)
	{
		printf("查无此人!\n");
		printf("\n");
	}
	else
	{
		int in_put = 0;
		do
		{
			menu_();
			scanf("%d", &in_put);
			switch (in_put)
			{
			case 1:
				printf("请输入修改后的姓名:->");
				scanf("%s", p->data[ret].name);
				system("cls");

				printf("姓名修改成功!\n");
				break;
			case 2:
				printf("请输入修改后的电话:->");
				scanf("%s", p->data[ret].tele);
				system("cls");

				printf("电话修改成功!\n");
				break;
			case 3:
				printf("请输入修改后的年龄:->");
				scanf("%d", &(p->data[ret].age));
				system("cls");

				printf("年龄修改成功!\n");
				break;
			case 4:
				printf("请输入修改后的住址:->");
				scanf("%s", p->data[ret].addr);
				system("cls");

				printf("住址修改成功!\n");
				break;
			case 5:
				printf("请输入修改后的性别:->");
				scanf("%s", p->data[ret].sex);
				system("cls");

				printf("性别修改成功!\n");
				break;
			case 0:
				printf("取消修改!\n");
				break;
			default:
				printf("输入错误!\n");
				break;
			}
		} while (in_put);
	}
}
//查找联系人信息
void Find_contact(const struct contact* p)
{
	assert(p);
	char del_name[NAME];
	printf("请输入要查找联系人的姓名:->");
	scanf("%s", del_name);
	system("cls");

	//查找该联系人
	int ret = find_name(p, del_name);
	if (ret == -1)
		printf("查无此人!\n");
	else
	{
		printf("%-20s\t%-5s\t%-12s\t%-20s\t%-5s\n", "姓名", "性别", "电话", "住址", "年龄");
		printf("%-20s\t%-5s\t%-12s\t%-20s\t%-5d\n", p->data[ret].name,
			p->data[ret].sex,
			p->data[ret].tele,
			p->data[ret].addr,
			p->data[ret].age);
	}
}
//排序菜单
void menu_sort()
{
	printf("******   1、姓名   ******\n");
	printf("******   2、住址   ******\n");
	printf("******   3、年龄   ******\n");
	printf("******   4、性别   ******\n");
	printf("******   0、退出   ******\n");
}

//姓名排序
int cmp_name(const void* e1, const void* e2)
{
	return strcmp(((struct message*)e1)->name, ((struct message*)e2)->name);
}
//住址排序
int cmp_addr(const void* e1, const void* e2)
{
	return strcmp(((struct message*)e1)->addr, ((struct message*)e2)->addr);
}
//年龄排序
int cmp_age(const void* e1, const void* e2)
{
	return ((struct message*)e1)->age - ((struct message*)e2)->age;
}
//性别排序
int cmp_sex(const void* e1, const void* e2)
{
	return strcmp(((struct message*)e1)->sex, ((struct message*)e2)->sex);
}
//排序联系人
void Sort_contact(struct contact* p)
{
	int s = 0;
	do
	{
		//排序菜单
		menu_sort();
		printf("请选择排序类型:->");
		scanf("%d", &s);
		system("cls");
		switch (s)
		{
		case 1:
			qsort(p->data, p->sz, sizeof(struct message), cmp_name);
			printf("排序成功!\n");
			break;
		case 2:
			qsort(p->data, p->sz, sizeof(struct message), cmp_addr);
			printf("排序成功!\n");
			break;
		case 3:
			qsort(p->data, p->sz, sizeof(struct message), cmp_age);
			printf("排序成功!\n");
			break;
		case 4:
			qsort(p->data, p->sz, sizeof(struct message), cmp_sex);
			printf("排序成功!\n");
			break;
		case 0:
			printf("退出排序\n");
			break;
		default:
			printf("输入有误!\n");
			break;
		}

	} while (s);
}

//清空联系人
void Clean(struct contact* p)
{
	p->sz = 0;
	printf("清空成功!\n");
}
//释放空间
void Destory_contact(struct contact* p)
{
	free(p->data);
	p->data=NULL;
	p->sz = 0;
	p->capacity = 0;
}



end
生活原本沉闷,但跑起来就会有风!

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

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

相关文章

优雅的使用Webstack打造个人网址导航

原文链接&#xff1a;优雅的使用Webstack打造个人网址导航 前言 一款基于 WebStackPage 的 Hexo 主题。本人选择的是 hexo-theme-webstack。 效果预览 具体效果请移步 个人网址导航。 步骤 在目标路径&#xff08;我这里选的路径为【D:/studytype/My_Blog】&#xff09;打开…

基于C#制作一个桌面宠物

此文主要基于C#制作一个桌面宠物&#xff0c;可自定义宠物素材图片及打开外部exe的快捷菜单。 实现流程1.1、创建项目1.2、准备素材1.3、控件设置&#xff08;1&#xff09;PictureBox控件&#xff08;2&#xff09;timer控件&#xff08;3&#xff09;contextMenuStrip控件1.4…

学习MySQL必须掌握的13个关键字,你get了吗?

1、三范式 第一范式&#xff1a;每个表的每一列都要保持它的原子性&#xff0c;也就是表的每一列是不可分割的&#xff1b;第二范式&#xff1a;在满足第一范式的基础上&#xff0c;每个表都要保持唯一性&#xff0c;也就是表的非主键字段完全依赖于主键字段&#xff1b;第三范…

【微服务】Nacos2.x服务发现?RPC调用?重试机制?

&#x1f496;Spring家族及微服务系列文章 ✨【微服务】Nacos通知客户端服务变更以及重试机制 【微服务】SpringBoot监听器机制以及在Nacos中的应用 ✨【微服务】Nacos服务端完成微服务注册以及健康检查流程 ✨【微服务】Nacos客户端微服务注册原理流程 ✨【微服务】SpringClou…

Vue 和 React 比,React 好在哪里?

​ 这两个设计理念上就有所区别&#xff0c;类比过来就是&#xff1a;Vue 是自动挡汽车&#xff0c;React 是手动挡汽车。 在 Vue 中&#xff0c;不需要去注意视图和数据的一致性&#xff0c;因为有双向绑定看帮你处理&#xff0c;响应式的。还有一些很方便的 v-if、v-model 之…

软考 - 面向对象开发

⭐设计模式UML详解&#xff1a;https://blog.csdn.net/qq_40274514/article/details/124047443 面向对象基础 面向对象的程序设计 和 面向对象设计区别 面向对象的程序设计涉及到具体的编程语言 面向对象设计只从系统逻辑结构设计解决方案 常见的机制 动态绑定&#xff1a;过…

ESXi5.5远程升级到ESXi6.7 (VMware Hypervisor)

1、ESXi的介质分为两类&#xff0c;以6.7为例&#xff1a; VMware vSphere Hypervisor (ESXi ISO) image (Includes VMware Tools)&#xff08;ISO包&#xff09; VMware vSphere Hypervisor (ESXi) Offline Bundle &#xff08;ZIP包&#xff09; 如果要升级&#xff0c;需要Z…

【畅购商城】详情页详情之商品详情

1.构建详情页 步骤0&#xff1a;确定访问路径 http://localhost:3000/Goods?id1 步骤二&#xff1a;复制 ~/static/goods.html 内容&#xff0c;导入第三方资源&#xff08;css、js&#xff09; head: {title: 列表页面,link: [{rel:stylesheet,href: /style/goods.css},{re…

Sysweld笔记:利用稳态算法加速算法模拟焊接过程的残余应力

作者&#xff1a;贾亚波博士&#xff0c;仿真秀专栏作者 在进行热力耦合的仿真过程中&#xff0c;如果模型足够的长并且热源速度恒定&#xff0c;通常其热学&#xff0c;相变以及热力耦合都会达到稳态的过程&#xff0c;因此如何直接计算稳态问题成为了大家研究的热点问题。 …

【C++笔试强训】第二十四天

&#x1f387;C笔试强训 博客主页&#xff1a;一起去看日落吗分享博主的C刷题日常&#xff0c;大家一起学习博主的能力有限&#xff0c;出现错误希望大家不吝赐教分享给大家一句我很喜欢的话&#xff1a;夜色难免微凉&#xff0c;前方必有曙光 &#x1f31e;。 &#x1f4a6;&a…

【数据结构】栈基本操作的实现(C语言)

&#x1f680; 作者简介&#xff1a;一名在后端领域学习&#xff0c;并渴望能够学有所成的追梦人。 &#x1f40c; 个人主页&#xff1a;蜗牛牛啊 &#x1f525; 系列专栏&#xff1a;&#x1f6f9;初出茅庐C语言、&#x1f6f4;数据结构 &#x1f4d5; 学习格言&#xff1a;博…

SpringBoot项目打包时配置文件区分日常、测试、预发、正式环境

前言&#x1f34a; 在我们开发项目的时候&#xff0c;一般有四套环境&#xff1a;日常、测试、预发、正式。日常环境作为我们开发环境&#xff1b;测试环境给测试同学测试功能&#xff1b;预发环境给正式环境发布时提供准备&#xff1b;正式环境则是稳定的生产环境。 这四套环…

面试官问我new Vue阶段做了什么?

前言 本篇录入吊打面试官专栏&#xff0c;希望能祝君拿下Offer一臂之力&#xff0c;各位看官感兴趣可移步&#x1f6b6;。这段时间面了很多家公司&#xff0c;被问到的题我感觉不重复不止100道&#xff0c;将会挑选觉得常见且有意义的题目进行分析及回答。有人说面试造火箭&am…

Redis字符串、hash、列表方法使用以及Redis管道与Django集成Redis

目录标题一、Redis字符串操作二、Redis-hash操作三、Redis列表操作四、Redis管道五、Redis其他操作六、Django中集成Redis七、Celery介绍一、Redis字符串操作 名称属性setex:过期时间&#xff08;秒&#xff09;px:过期时间(毫秒) nx:如果设置为True&#xff0c;则只有name不存…

毕业设计:SpringBoot+Vue+Element的校内跑腿平台

作者主页&#xff1a;编程指南针 作者简介&#xff1a;Java领域优质创作者、CSDN博客专家 、掘金特邀作者、多年架构师设计经验、腾讯课堂常驻讲师 主要内容&#xff1a;Java项目、毕业设计、简历模板、学习资料、面试题库、技术互助 文末获取源码 项目编号&#xff1a;BS-XX-…

MySQL基础总结

一.sql数据及语言基本类型: 1.语言的分类 DDL:数据定义语言,用来定义数据库对象:数据库,表,列等。关键字:create,alter,drop等 DML:数据操作语言,用来对数据库中表的记录进行操作。关键字:insert,delete,update等 DQL:数据库查询语言,用来查询数据库中表的记录。关键字:select,…

PIX2SEQ: A LANGUAGE MODELING FRAMEWORK FOR OBJECT DETECTION

文章目录ABSTRACT1 INTRODUCTION2 pix2seq框架2.1SEQUENCE CONSTRUCTION FROM OBJECT DESCRIPTIONS2.2 ARCHITECTURE, OBJECTIVE AND INFERENCE2.3 SEQUENCE AUGMENTATION TO INTEGRATE TASK PRIORS3 EXPERIMENTS3.1 EXPERIMENTAL SETUP3.2 MAIN COMPARISONS3.3 ABLATION ON SE…

2022年都在说软件测试饱和了?都在担心面试不上。

今年开始&#xff0c;小编听到最多的问题就是 软件测试行业是不是饱和了&#xff1f; 软件测试行业还有前景吗&#xff1f; 无非是因为投出去的简历回复的越来越少了 据中华英才网统计&#xff0c;目前软件测试人才的缺口在100万人以上&#xff0c;并以每年20%的速度递增&am…

2.5 自定义srv C++

功能介绍 以自定义数据类型为基础&#xff0c;完成一个节点作为服务器&#xff0c;另一个节点接收传送两个数字到服务端&#xff0c;服务端计算后反馈到客户端进行打印输出 1、工作空间 1.1 创建工作空间lee_ws mkdir -p ~/lee_ws/src cd ~/lee_ws/src/ catkin_init_worksp…

Unity 旋转大总结和项目操作

操作演示 旋转 (online-video-cutter.com)旋转方法都放在了按钮上&#xff0c;第一个是初始化按钮&#xff0c;将cube恢复到&#xff08;0&#xff0c;0&#xff0c;0&#xff09;&#xff0c;但是位置不会变成&#xff08;0&#xff0c;0&#xff0c;0&#xff09; 这个是参…