通讯录应用程序开发指南

目录

一、前言

二、构建通讯录应用程序

2.1通讯录框架

(1)打印菜单

(2) 联系人信息的声明

(3)创建通讯录

(4)初始化通讯录

2.2功能实现 

(1)增加联系人

(2)显示联系人

(3)删除联系人

(4)查找联系人

(5)修改联系人

(6)排序联系人

三、通讯录的优化

3.1 文件存储

🌴保存信息到文件中:

🌴加载文件中的信息到通讯录:

3.2 动态开辟内存

🌴创建通讯录 :

🌴初始化通讯录: 

🌴增加联系人:

 🌴销毁通讯录:

四、源码


一、前言

在日常生活中,我们经常需要管理大量的联系人信息,包括电话号码、电子邮件地址等。通讯录应用程序成为了我们生活中不可或缺的一部分,它可以帮助我们高效的管理和查找联系人信息。在本篇博客中,我们将探讨如何使用C语言编写一个简单的通讯录应用程序。通过学习这个实例,我们将了解如何使用C语言来处理数据、实现基本的增删查改功能,并且获得实际的编程实际经验。

二、构建通讯录应用程序

本篇博客所实现的通讯录有如下功能:

  1. 可以保存100个人(人数由自己控制)的信息;
  2. 增加联系人的信息;
  3. 删除指定联系人的信息;
  4. 查找指定联系人的信息;
  5. 修改指定联系人的信息;
  6. 显示所有联系人的信息
  7. 排序通讯录的信息。

联系人的信息有:名字、年龄、性别、电话、住址。

2.1通讯录框架

(1)打印菜单

为了能够实现人机交互,我们需要打印菜单以供用户选择想要实现的功能。

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

enum Option
{
	EXIT,//0
	ADD,//1
	DEL,//2
	SEARCH,//3
	MODIFY,//4
	SHOW,//5
	SORT//6
};

int main()
{
	int input = 0;
	do
	{
		menu();
		printf("请输入您的选择:>");
		scanf("%d", &input);
		switch (input)
		{
		case ADD:
			break;
		case DEL:
			break;
		case SEARCH:
			break;
		case MODIFY:
			break;
		case SHOW:
			break;
		case SORT:
			break;
		case EXIT:
			printf("退出通讯录\n");
			break;
		default:
			printf("选择错误,请重新选择!\n");
			break;
		}

	} while (input);

	return 0;
}

🌴打印效果:

(2) 联系人信息的声明

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

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

(3)创建通讯录

#define MAX 100

typedef struct Contact
{
	PeoInfo data[MAX];//存放联系人的数据
	int sz;//记录当前通讯录中存放的人的信息个数
}Contact;

(4)初始化通讯录

void InitContact(Contact* pc)
{
	assert(pc);//保证指针的有效性

	memset(pc->data, 0, sizeof(pc->data));
	pc->sz = 0;
}

2.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("%s", &(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");
}

🌴效果:

(2)显示联系人

联系人增加成功后,我们想看到他的所有信息,这时候我们就可以让他显示在屏幕上。 

void ShowContact(const Contact* pc)
{
	assert(pc);

	//判断通讯录是否为空,如果为空,则无需打印
	if (pc->sz == 0)
	{
		printf("通讯录为空!\n");
		return;
	}

	//为了增加美观性,打印标题行
	printf("%-20s%-5s%-5s%-15s%-30s\n", "姓名", "年龄", "性别", "电话", "地址");
	for (int i = 0; i < pc->sz; i++)
	{
		printf("%-20s%-5d%-5s%-15s%-30s\n", 
			pc->data[i].name, pc->data[i].age, pc->data[i].sex, pc->data[i].tele, pc->data[i].addr);
	}
}

🌴效果:

(3)删除联系人

我们发现,不管是删除联系人,还是修改联系人,我们首先要找到这个联系人,所以我们还要写一个查找联系人的函数。 查找联系人的过程就是将这个通讯录遍历一遍,找到它的每个元素,然后跟我们要查找的这个人相比较,如果相同,就返回这个元素的下标,如果找不到,就返回-1。

//查找联系人
int FindByContact(Contact* pc, char name[])
{
	assert(pc);

	for (int 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];

	//判断通讯录是否为空,如果为空,则无需删除
	if (pc->sz == 0)
	{
		printf("通讯录为空,无需删除\n");
		return;
	}

	//查找联系人
	printf("请输入要删除联系人的名字:");
	scanf("%s", name);
	int ret = FindByContact(pc, name);
	if (ret == -1)
	{
		printf("查无此人\n");
		return;
	}
	//删除联系人
	for (int i = ret; i < pc->sz - 1; i++)
	{
		pc->data[i] = pc->data[i + 1];
	}
	pc->sz--;
	printf("删除成功\n");
}

 🌴效果:

(4)查找联系人

void SearchContact(Contact* pc)
{
	assert(pc);
	char name[NAME_MAX];
	printf("请输入要查找人的姓名:");
	scanf("%s", name);
	int ret = FindByContact(pc, name);
	if (ret == -1)
	{
		printf("查无此人\n");
		return;
	}
	//显示联系人
	printf("%-20s%-5s%-5s%-15s%-30s\n", "姓名", "年龄", "性别", "电话", "地址");
	printf("%-20s%-5d%-5s%-15s%-30s\n",
		pc->data[ret].name, pc->data[ret].age, pc->data[ret].sex, pc->data[ret].tele, pc->data[ret].addr);
}

  🌴效果:

(5)修改联系人

void ModifyContact(Contact* pc)
{
	int input = 0;
	assert(pc);
	char name[NAME_MAX];
	printf("请输入要修改人的姓名:");
	scanf("%s", name);
	int ret = FindByContact(pc, name);
	if (ret == -1)
	{
		printf("查无此人\n");
		return;
	}
	//修改信息
	do
	{
		printf("请选择要修改的信息:%s %s %s %s %s %s\n", "1.姓名", "2.年龄", "3.性别", "4.电话", "5.地址", "0.退出");
		scanf("%d", &input);
		switch (input)
		{
		case 1:
			printf("请输入要修改人的姓名:\n");
			scanf("%s", pc->data[ret].name);
			printf("修改成功\n");
			break;
		case 2:
			printf("请输入要修改人的年龄:\n");
			scanf("%d", &(pc->data[ret].age));
			printf("修改成功\n");
			break;
		case 3:
			printf("请输入要修改人的性别:\n");
			scanf("%s", pc->data[ret].sex);
			printf("修改成功\n");
			break;
		case 4:
			printf("请输入要修改人的电话:\n");
			scanf("%s", pc->data[ret].tele);
			printf("修改成功\n");
			break;
		case 5:
			printf("请输入要修改人的地址:\n");
			scanf("%s", pc->data[ret].addr);
			printf("修改成功\n");
			break;
		case 0:
			printf("退出修改\n");
			break;
		default:
			printf("修改项中没有此信息,请重新选择\n");
			break;
		}
	} while (input);
}

 🌴效果:

 

(6)排序联系人

//比较函数,用于qsort排序
int compareByAge(const void* a, const void* b)
{
	return ((PeoInfo*)a)->age - ((PeoInfo*)b)->age;
}

//排序联系人
void SortContactAge(Contact* pc)
{
	assert(pc);
	if (pc->sz == 0)
	{
		printf("通讯录为空,无需排序!\n");
		return;
	}
	qsort(pc->data, pc->sz, sizeof(PeoInfo), compareByAge);
	printf("%-20s%-5s%-5s%-15s%-30s\n", "姓名", "年龄", "性别", "电话", "地址");
	for (int i = 0; i < pc->sz; i++)
	{
		printf("%-20s%-5d%-5s%-15s%-30s\n",
			pc->data[i].name, pc->data[i].age, pc->data[i].sex, pc->data[i].tele, pc->data[i].addr);
	}

	printf("排序成功!\n");
}

  🌴效果:

三、通讯录的优化

当我们将上面实现的通讯录运行起来后,我们会发现以下几点问题:

  1. 录入的信息等程序结束后,就不存在了,这是因为数据是存放在内存中的,只要程序退出,或者掉电,都会丢失。
  2. 我们可以发现通讯录的大小是固定的100个元素,可以存放100个人的信息,但如果信息太多,空间就会有点小,不够用;而信息太少,空间又会太大,造成空间的浪费。

那该怎么解决呢?

  • 对于第1点,我们可以使用文件存储或数据库存储的方式来保存录入的联系人信息。
  • 对于第2点,我们可以用动态内存开辟的方式来开辟空间。

3.1 文件存储

🌴保存信息到文件中:

//保存信息到文件中去
void SaveContact(Contact* pc)
{
	//打开文件
	FILE* pf = fopen("contact.txt", "wb");
	if (pf == NULL)
	{
		perror("SaveContact");
		return;
	}
	//写数据
	int i = 0;
	for (i = 0; i < pc->sz; i++)
	{
		fwrite(pc->data + i, sizeof(PeoInfo), 1, pf);
	}
	//关闭文件
	fclose(pf);
	pf = NULL;
}

🌴加载文件中的信息到通讯录:

void Checkcapacity(Contact* pc);//声明增容函数

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


//文件版本的初始化函数
void InitContact(Contact* pc)
{
	assert(pc);//保证指针的有效性

	pc->sz = 0;
	pc->capacity = DEFAULT_SZ;
	pc->data = calloc(DEFAULT_SZ, sizeof(PeoInfo));
	if (pc->data == NULL)
	{
		perror("InitContact->calloc");
		return;
	}
	//加载文件中的信息到通讯录
	LoadContact(pc);
}

3.2 动态开辟内存

  1. 让通讯录刚开始时存放3个人的信息。
  2. 空间如果放满,可以增加容量,每次增加2个人的信息的空间。

🌴创建通讯录 :

 将data数组改为指针变量用来接收calloc函数开辟空间后的地址;增加一个变量capacity用来记录通讯录的当前容量,如果存放的信息满3个人,则增加容量。

//动态通讯录的版本
typedef struct Contact
{
	PeoInfo* data;//存放数据
	int sz;//记录当前通讯录中存放的人的信息个数
	int capacity;//记录的是通讯录的当前容量
}Contact;

🌴初始化通讯录: 

将通讯录容量初始化为3,这里可以定义宏,以方便修改,再用calloc函数开辟空间。

//动态版本
#define DEFAULT_SZ 3

void InitContact(Contact* pc)
{
	assert(pc);//保证指针的有效性

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

🌴增加联系人:

当通讯录满了以后,我们要考虑增容的问题,所以还要修改增加函数,将每次要增加的容量也定义为宏,方便修改。

//动态版本
#define DEFAULT_INC 2

void Checkcapacity(Contact* pc)
{
	if (pc->sz == pc->capacity)
	{
		PeoInfo* ptr = (PeoInfo*)realloc(pc->data, (pc->capacity + DEFAULT_INC) * sizeof(PeoInfo));
		if (ptr == NULL)
		{
			pc->data = ptr;
			pc->capacity += DEFAULT_INC;
	        printf("增容成功!\n");
		}
		else
		{
			perror("AddContact->recalloc");
			return;
		}
	}
}

 void AddContact(Contact* pc)
{
	assert(pc);
	//增加容量
	Checkcapacity(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].tele);
	printf("请输入联系人的地址:");
	scanf("%s", pc->data[pc->sz].addr);

	pc->sz++;
	printf("联系人添加成功\n");
}

 🌴销毁通讯录:

当我们要退出通讯录的时候,要将realloc函数开辟的空间释放掉。

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

四、源码

🌻(test.c )

#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("***  0.exit                   ***\n");
	printf("*********************************\n");
}

enum Option
{
	EXIT,//0
	ADD,//1
	DEL,//2
	SEARCH,//3
	MODIFY,//4
	SHOW,//5
	SORT//6
};

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 SEARCH:
			SearchContact(&con);
			break;
		case MODIFY:
			ModifyContact(&con);
			break;
		case SHOW:
			ShowContact(&con);
			break;
		case SORT:
			SortContactAge(&con);
			break;
		case EXIT:
			//保存信息到文件
			SaveContact(&con);
			//销毁通讯录
			DestoryContact(&con);
			printf("退出通讯录\n");
			break;
		default:
			printf("选择错误,请重新选择!\n");
			break;
		}

	} while (input);

	return 0;
}

 🌻(contact.h)

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

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

#define MAX 100

#define DEFAULT_SZ 3
#define DEFAULT_INC 2

typedef struct PeoInfo
{
	char name[NAME_MAX];
	int age;
	char sex[SEX_MAX];
	char tele[TELE_MAX];
	char addr[ADDR_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 AddContact(Contact* pc);

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

//删除联系人的信息
void DelContact(Contact* pc);

//查找联系人的信息
void SearchContact(Contact* pc);

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

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

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

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

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

 🌻(contact.c)

#include "Contact.h"

//初始化通讯录
// 静态版本
//void InitContact(Contact* pc)
//{
//	assert(pc);//保证指针的有效性
//
//	memset(pc->data, 0, sizeof(pc->data));
//	pc->sz = 0;
//}

void Checkcapacity(Contact* pc);//声明增容函数

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


//文件版本的初始化函数
void InitContact(Contact* pc)
{
	assert(pc);//保证指针的有效性

	pc->sz = 0;
	pc->capacity = DEFAULT_SZ;
	pc->data = calloc(DEFAULT_SZ, sizeof(PeoInfo));
	if (pc->data == NULL)
	{
		perror("InitContact->calloc");
		return;
	}
	//加载文件中的信息到通讯录
	LoadContact(pc);
}

动态版本的初始化函数
//void InitContact(Contact* pc)
//{
//	assert(pc);//保证指针的有效性
//
//	pc->sz = 0;
//	pc->capacity = DEFAULT_SZ;
//	pc->data = calloc(DEFAULT_SZ , sizeof(PeoInfo));
//	if (pc->data == NULL)
//	{
//		perror("InitContact->calloc");
//		return;
//	}
//}

//增加联系人信息
//静态版本
//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].tele);
//	printf("请输入联系人的地址:");
//	scanf("%s", pc->data[pc->sz].addr);
//
//	pc->sz++;
//	printf("联系人添加成功\n");
//}

void Checkcapacity(Contact* pc)
{
	if (pc->sz == pc->capacity)
	{
		PeoInfo* ptr = (PeoInfo*)realloc(pc->data, (pc->capacity + DEFAULT_INC) * sizeof(PeoInfo));
		if (ptr != NULL)
		{
			pc->data = ptr;
			pc->capacity += DEFAULT_INC;
			printf("增容成功!\n");
		}
		else
		{
			perror("AddContact->recalloc");
			return;
		}
	}
}

//动态版本
 void AddContact(Contact* pc)
{
	assert(pc);
	//增加容量
	Checkcapacity(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].tele);
	printf("请输入联系人的地址:");
	scanf("%s", pc->data[pc->sz].addr);

	pc->sz++;
	printf("联系人添加成功\n");
}

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

	//判断通讯录是否为空,如果为空,则无需打印
	if (pc->sz == 0)
	{
		printf("通讯录为空!\n");
		return;
	}

	//为了增加美观性,打印标题行
	printf("%-20s%-5s%-5s%-15s%-30s\n", "姓名", "年龄", "性别", "电话", "地址");
	for (int i = 0; i < pc->sz; i++)
	{
		printf("%-20s%-5d%-5s%-15s%-30s\n", 
			pc->data[i].name, pc->data[i].age, pc->data[i].sex, pc->data[i].tele, pc->data[i].addr);
	}
}

//查找联系人
int FindByContact(Contact* pc, char name[])
{
	assert(pc);

	for (int 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];

	//判断通讯录是否为空,如果为空,则无需删除
	if (pc->sz == 0)
	{
		printf("通讯录为空,无需删除\n");
		return;
	}

	//查找联系人
	printf("请输入要删除联系人的名字:");
	scanf("%s", name);
	int ret = FindByContact(pc, name);
	if (ret == -1)
	{
		printf("查无此人\n");
		return;
	}
	//删除联系人
	for (int i = ret; i < pc->sz - 1; i++)
	{
		pc->data[i] = pc->data[i + 1];
	}
	pc->sz--;
	printf("删除成功\n");
}

//查找联系人的信息
void SearchContact(Contact* pc)
{
	assert(pc);
	char name[NAME_MAX];
	printf("请输入要查找人的姓名:");
	scanf("%s", name);
	int ret = FindByContact(pc, name);
	if (ret == -1)
	{
		printf("查无此人\n");
		return;
	}
	//显示联系人
	printf("%-20s%-5s%-5s%-15s%-30s\n", "姓名", "年龄", "性别", "电话", "地址");
	printf("%-20s%-5d%-5s%-15s%-30s\n",
		pc->data[ret].name, pc->data[ret].age, pc->data[ret].sex, pc->data[ret].tele, pc->data[ret].addr);
}

//修改联系人
void ModifyContact(Contact* pc)
{
	int input = 0;
	assert(pc);
	char name[NAME_MAX];
	printf("请输入要修改人的姓名:");
	scanf("%s", name);
	int ret = FindByContact(pc, name);
	if (ret == -1)
	{
		printf("查无此人\n");
		return;
	}
	
	do
	{
		printf("请选择要修改的信息:%s %s %s %s %s %s\n", "1.姓名", "2.年龄", "3.性别", "4.电话", "5.地址", "0.退出");
		scanf("%d", &input);
		switch (input)
		{
		case 1:
			printf("请输入要修改人的姓名:\n");
			scanf("%s", pc->data[ret].name);
			printf("修改成功\n");
			break;
		case 2:
			printf("请输入要修改人的年龄:\n");
			scanf("%d", &(pc->data[ret].age));
			printf("修改成功\n");
			break;
		case 3:
			printf("请输入要修改人的性别:\n");
			scanf("%s", pc->data[ret].sex);
			printf("修改成功\n");
			break;
		case 4:
			printf("请输入要修改人的电话:\n");
			scanf("%s", pc->data[ret].tele);
			printf("修改成功\n");
			break;
		case 5:
			printf("请输入要修改人的地址:\n");
			scanf("%s", pc->data[ret].addr);
			printf("修改成功\n");
			break;
		case 0:
			printf("退出修改\n");
			break;
		default:
			printf("修改项中没有此信息,请重新选择\n");
			break;
		}
	} while (input);
}

//比较函数,用于qsort排序
int compareByAge(const void* a, const void* b)
{
	return ((PeoInfo*)a)->age - ((PeoInfo*)b)->age;
}

//排序联系人
void SortContactAge(Contact* pc)
{
	assert(pc);
	if (pc->sz == 0)
	{
		printf("通讯录为空,无需排序!\n");
		return;
	}
	qsort(pc->data, pc->sz, sizeof(PeoInfo), compareByAge);
	printf("%-20s%-5s%-5s%-15s%-30s\n", "姓名", "年龄", "性别", "电话", "地址");
	for (int i = 0; i < pc->sz; i++)
	{
		printf("%-20s%-5d%-5s%-15s%-30s\n",
			pc->data[i].name, pc->data[i].age, pc->data[i].sex, pc->data[i].tele, pc->data[i].addr);
	}

	printf("排序成功!\n");
}

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

//保存信息到文件中去
void SaveContact(Contact* pc)
{
	//打开文件
	FILE* pf = fopen("contact.txt", "wb");
	if (pf == NULL)
	{
		perror("SaveContact");
		return;
	}
	//写数据
	int i = 0;
	for (i = 0; i < pc->sz; i++)
	{
		fwrite(pc->data + i, sizeof(PeoInfo), 1, pf);
	}
	//关闭文件
	fclose(pf);
	pf = NULL;
}

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

机器学习——分类评价指标

【说明】文章内容来自《机器学习——基于sklearn》&#xff0c;用于学习记录。若有争议联系删除。 1、评价指标 对于模型的评价往往会使用损失函数和评价指标&#xff0c;两者的本质是一致的。一般情况下&#xff0c;损失函数应用于训练过程&#xff0c;而评价指标应用于测试过…

代码随想录-刷题第三十四天

1005. K 次取反后最大化的数组和 题目链接&#xff1a;1005. K 次取反后最大化的数组和 思路&#xff1a;取反k次&#xff0c;保证每次取反的数值是数组中的最小值&#xff0c;最后数组和就是最大的。 class Solution {public int largestSumAfterKNegations(int[] nums, in…

pdf 在线编辑

https://smallpdf.com/edit-pdf#rapp 参考 https://zh.wikihow.com/%E5%B0%86%E5%9B%BE%E5%83%8F%E6%8F%92%E5%85%A5PDF

直排轮滑教程4

蹬地 1&#xff0c;前面练习了蹬地的结构&#xff0c;知道蹬地方向&#xff0c;如何用力。下面来练习具体的蹬地的方法&#xff0c;轮滑蹬地有自己特点。 2&#xff0c;技术方法和特点&#xff1a;蹬地速度快&#xff0c;蹬地有弹性。似跳非跳蹬。 3&#xff0c;四轮着地。轮…

GitHub打不开或者访问慢解决方法

一、获取IP地址 首先进入下面的网站 IP/DNS Detect 获取到当前github.com对应的IP地址 可以多search几次, github.com对应的IP地址不止一个,都记录下来 二、修改hosts文件内容 找到文件夹路径&#xff1a;C:\Windows\System32\drivers\etc\ 打开hosts文件&#xff0c;将刚才…

simulink代码生成(一)——环境搭建

一、安装C2000的嵌入式环境&#xff1b; 点击matlab附加功能&#xff0c; 然后搜索C2000&#xff0c;安装嵌入式硬件支持包&#xff1b;点击安装即可&#xff1b;&#xff08;目前还不知道破解版的怎么操作&#xff0c;目前我用的是正版的这样&#xff0c;完全破解的可能操作…

达梦到达梦的外部链接dblink(DM-DM DBLINK)

一. 使用场景&#xff1a; 部链接对象&#xff08;LINK&#xff09;是 DM 中的一种特殊的数据库实体对象&#xff0c;它记录了远程数据库的连接和路径信息&#xff0c;用于建立与远程数据的联系。通过多台数据库主库间的相互通讯&#xff0c;用户可以透明地操作远程数据库的数…

EDA实验-----直流电机驱动设计(Quartus II )

目录 一、实验目的 二、实验仪器设备 三、实验的重点和难点 四、实验原理 五、实验步骤 六、实验报告 七、实验过程 1.分频器代码 2.方向选择器 3.直流电动机工作原理 4.电路连接图 5.文件烧录 一、实验目的 了解直流电机控制的工作原理和实现的方法。掌握PWM波控…

OpenGL glLineWidth失效问题

文章目录 一、问题描述二、解决方法 一、问题描述 之前在使用OpenGL时&#xff0c;突然发现glLineWidth失效了&#xff0c;也就是怎么设置线宽都没反应&#xff0c;也使用了一些方法检测了自己的电脑是否支持线宽&#xff08;其实大部分电脑都支持&#xff09;&#xff0c;最后…

IgH调试注意事项

1&#xff0c;不要在虚拟机测试&#xff0c;否则IgH无法收发数据包 现象&#xff1a;虚拟机中运行IgH master并绑定网卡后&#xff0c;主站由ORPHANED状态转换成IDLE状态&#xff0c;但无法收发数据报。 这是因为虚拟机用的是虚拟网卡&#xff0c;需通过iptables将数据包到转…

基于SSM的旅游网站设计与实现

末尾获取源码 开发语言&#xff1a;Java Java开发工具&#xff1a;JDK1.8 后端框架&#xff1a;SSM 前端&#xff1a;采用JSP技术开发 数据库&#xff1a;MySQL5.7和Navicat管理工具结合 服务器&#xff1a;Tomcat8.5 开发软件&#xff1a;IDEA / Eclipse 是否Maven项目&#x…

WSL移动ubuntu到其他盘的几个问题以及安装,使用过程中遇到bug记录

这里写目录标题 无法正常修改Ubuntu系统的默认用户解决方案1&#xff1a;解决方案2&#xff1a; 出现 id xxx no such userGUI不能正常显示 无法正常修改Ubuntu系统的默认用户 ubuntu移动到其他盘可以参考WSL Ubuntu子系统迁移到非系统盘 下面问题是我安装时遇到的&#xff0c…

蓝桥杯c/c++程序设计——接龙数组

问题描述 对于一个长度为 K的整数数列&#xff1a;A1,A2,...,AK我们称之为接龙数列当且仅当 Ai 的首位数字恰好等于 Ai−1的末位数字 (2≤i≤K)。 例如 12,23,35,56,61,1112,23,35,56,61,11 是接龙数列&#xff1b;12,23,34,5612,23,34,56 不是接龙数列&#xff0c;因为 56 的…

蓝桥杯:日期问题

目录 引言一、日期问题1.题目描述2.代码实现3.测试 二、回文日期1.题目描述2.代码实现3.测试 引言 关于这个蓝桥杯的日期问题&#xff0c;其实有一个明确的思路就感觉很简单&#xff0c;这个思路就是不用依照日期的顺序去把每一天走完&#xff0c;而是根据一个数加一&#xff…

生成模型 | 三维重建(3D reconstruction)调研及总结【20231219更新版】

本文是关于三维重建的论文调研&#xff0c;主要集中于基于图片到3d的模型&#xff0c;其中期刊会议标志如下&#xff1a; [&#x1f916; ICCV 2023 ] 1.3D综述系列 2019_Image-based 3D Object Reconstruction: State-of-the-Art and Trends in the Deep Learning Era 论文地…

树莓派,opencv,Picamera2利用舵机云台追踪人脸(PID控制)

一、需要准备的硬件 Raspiberry 4b两个SG90 180度舵机&#xff08;注意舵机的角度&#xff0c;最好是180度且带限位的&#xff0c;切勿选360度舵机&#xff09;二自由度舵机云台&#xff08;如下图&#xff09;Raspiberry CSI 摄像头 组装后的效果&#xff1a; 二、项目目标…

【K8s】4# 使用kuboard部署开源项目实战

文章目录 1.开源项目2.实战2.1.创建spring-blade命名空间2.2.导入 spring-blade 到 K8S 名称空间2.3.设置存储卷参数2.4.调整节点端口2.5.确认导入2.6.查看集群2.7.导入配置到 nacos2.8.启动微服务工作负载 3.验证部署结果3.1.Nacos3.2. web 4.问题汇总Q1&#xff1a;Nacos启动…

Blender插件-The Grove 10 树木生长动画植物插件

注意&#xff1a;Blender和The Grove的版本匹配。 亲测Blender 2.9与The Grove 10可以配合使用&#xff0c;Blender 3.6会报错&#xff0c;具体看报错记录。 一、下载 CG咖官网地址&#xff1a; Blender插件-树木生长插件植物生成插件 The Grove 10插件资产库 CSDN下载地址…

EasyExcel使用: RGB字体,RGB背景颜色,fillForegroundColor颜色对照表

EasyExcel使用: RGB字体&#xff0c;RGB背景颜色&#xff0c;fillForegroundColor颜色对照表 使用EasyExcel导出表格可能会对字体颜色和单元格背景颜色进行自定义的修改。 可以自定义字体颜色或者每个单元格的颜色 要想自定义颜色&#xff0c;需要重写CellWriteHandler接口&am…

gem5 garnet l1 l2 cache的创建与相连

gem5 garnet l1 l2 cache的创建与相连 主要就是这个图&#xff1a; 细节 我们用的是gem5/configs/deprecated/example/fs.py #fs.py 引入了上两层路径&#xff0c;也就是当前可以看到 gem5/configs/路径。 addToPath("../../")#fs.py引入了gem5/configs/ruby/Ru…