通讯录--动态版

news2024/11/27 1:16:16

简易的通讯录往往需要朴实的“烹饪”就能完成一道“美味的佳肴”。
我们需要一个通讯录,能够存储联系人的信息,能够对联系人的信息进行增删查改,查询,按姓名排序。相比对之前的三子棋、扫雷,有了一定的了解,这里对通讯录的感受也变得更加简单易懂。

在这里插入图片描述

通讯录--动态版

  • 一、Contact.h
  • 二、test.c
  • 三、Contact.c
  • 四、演示
    • 4.1添加联系人
    • 4.2显示联系人
    • 4.3查询联系人
    • 4.4修改联系人
    • 4.5排序联系人
    • 4.6删除联系人
    • 4.7清空联系人

一、Contact.h

#define _CRT_SECURE_NO_WARNINGS 1
#pragma warning(disable:6031)
//包含文件的声明,及一些结构的定义,在其他文件使用时就可以引用该头文件
#include <stdio.h>
#include <string.h>
#include <assert.h>
#include <stdlib.h>

#define MAX 100
#define NAME_MAX 20
#define SEX_MAX 5
#define TEL_MAX 12
#define ADDR_MAX 30
//动态版
#define DEFAULT_SZ 3
#define CAPACITY_SZ 2

enum OPTION//在上一篇章我们进一步加深了枚举的认识,这里我们正好使用枚举可以在进行选择时,更好的理解我们的选项是在干嘛
{
	EXIT,//默认从0开始,往下依次递增,EXIT==0
	ADD,//ADD==1
	DEL,//2
	SEARCH,//3
	MODIFY,//4
	SHOW,//5
	SORT,//6
	//动态
	EMPTY//7
};

//联系人的信息
typedef struct PeopleInfo//存储人的信息
{
	char name[NAME_MAX];
	int age;
	char sex[SEX_MAX];
	char tel[TEL_MAX];
	char addr[ADDR_MAX];
}PeopleInfo;
//静态版
//typedef struct Contact
//{
//	PeopleInfo data[MAX];
//	int sz;
//}Contact;

//动态版
typedef struct Contact
{
	PeopleInfo* data;
	int sz;
	int capacity;
}Contact;


//初始化通讯录
void InitContact(Contact* pc);

//添加联系人
void AddContact(Contact* pc);

//显示联系人
void ShowContact(const Contact* pc);//这里是显示联系人,并不需要对人的信息进行任何改变,可以用const来限定,防止信息被修改

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

//查询联系人
void SearchContact(const Contact* pc);//这里是查询信息,不需要做任何修改,可以用const来限定,防止信息被修改

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

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

二、test.c

#include "Contact.h"
void menu()//简易菜单
{
	printf("*********1.add       2.del*********\n");
	printf("*********3.search    4.modify******\n");
	printf("*********5.show      6.sort********\n");
	printf("*********0.exit *******************\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 EMPTY:
			EmptyContact(&con);
			break;
		case EXIT:
			DestroyContact(&con);
			printf("退出\n");
			break;
		default:
			printf("选择错误,请重新输入\n");
		}
	} while (input);
}
int main()
{
	test();
	return 0;
}

三、Contact.c

//函数的具体实现
#include "Contact.h"
//封装在contact.c中的内部函数,不暴露在外面,而contact.h中的函数声明是暴露出来的
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 InitContact(Contact* pc)
//{
//	assert(pc);
//	memset(pc->data, 0, sizeof(PeopleInfo)*MAX);
//	pc->sz = 0;
//}
//
//
//
添加联系人
//void AddContact(Contact* pc)
//{
//	assert(pc);
//	if (pc->sz == MAX)//判断通讯录是否已满
//	{
//		printf("通讯录已满,添加失败\n");
//		return;
//	}
//	int i = 0;
//	for(i=pc->sz; i<=pc->sz; i++)
//	{
//		printf("请输入添加人的姓名:");
//		scanf("%s", pc->data[i].name);
//		printf("请输入添加人的年龄:");
//		scanf("%d", &(pc->data[i].age));
//		printf("请输入添加人的性别:");
//		scanf("%s", pc->data[i].sex);
//		printf("请输入添加人的电话:");
//		scanf("%s", pc->data[i].tel);
//		printf("请输入添加人的地址:");
//		scanf("%s", pc->data[i].addr);
//		printf("成功添加联系人\n");
//	}
//	pc->sz++;
//}


//动态版
int CheckCapacity(Contact* pc)
{
	if (pc->sz == pc->capacity)
	{
		PeopleInfo* ps = (PeopleInfo*)realloc(pc->data,(pc->capacity + CAPACITY_SZ) * sizeof(PeopleInfo));
		if (ps == NULL)
		{
			perror("CheckCapacity");
			return 0;
		}
		else
		{
			pc->data = ps;
			pc->capacity += CAPACITY_SZ;
			printf("增容成功\n");
			return 1;
		}
	}
	return 1;
}
//初始化通讯录
void InitContact(Contact* pc)
{
	assert(pc);
	pc->data = (PeopleInfo*)malloc(DEFAULT_SZ * sizeof(PeopleInfo));
	pc->sz = 0;
	pc->capacity = DEFAULT_SZ;
}


//添加联系人
void AddContact(Contact* pc)
{
	assert(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].tel);
	printf("请输入添加人的地址:");
	scanf("%s", pc->data[pc->sz].addr);
	printf("成功添加联系人\n");
	pc->sz++;
}

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

//删除联系人--版本1
//void DelContact(Contact* pc)
//{
//	assert(pc);
//	char name[20] = { 0 };//为了能够输入删除人的姓名,我们得要一个能够存储所想要删除人的姓名
//	printf("请输入你要删除人的姓名:");
//	scanf("%s", name);
//	int i = 0;
//	int ret;
//	int flag = 0;
//	for (i = 0; i < pc->sz; i++)
//	{
//		if (strcmp(pc->data[i].name, name) == 0)
//		{
//			ret = i;
//			flag = 1;//删除的人存在,就置为1
//			break;
//		}
//	}
	for (i = ret; i < pc->sz - 1; i++)
	{
		pc->data[i] = pc->data[i + 1];
	}
	printf("成功删除联系人\n");
	pc->sz--;
//	//除了上面的这种方法,在上一章节我们已经学过了memmove,在这里也可以使用了,将ret+1位置开始到我们需要移动的字节大小移动到ret这个位置
//	//这样也成功的覆盖了一个人的信息
//	memmove(pc->data + ret, pc->data + ret + 1, sizeof(PeopleInfo) * (pc->sz - 1 - ret));
//	printf("成功删除联系人\n");
//	pc->sz--;//删除一个人的联系后,成员大小也要减一
//}

//删除联系人--版本2
void DelContact(Contact* pc)
{
	assert(pc);//断言
	char name[20] = { 0 };//为了能够输入删除人的姓名,我们得要一个能够存储所想要删除人的姓名
	printf("请输入你要删除人的姓名:");
	scanf("%s", name);
	//相对于版本1,这里将输入的人的姓名是否为通讯录中的姓名封装成一个内部函数
	int pos = FindName(pc, name);

	if (pos == -1)//删除的人不存在则返回
	{
		printf("要删除的联系人不存在\n");
		return;
	}
	memmove(pc->data + pos, pc->data + pos + 1, sizeof(PeopleInfo) * (pc->sz - 1 - pos));
	printf("成功删除联系人\n");
	pc->sz--;//删除一个人的联系后,成员大小也要减一
}

//查询联系人
void SearchContact(const Contact* pc)
{
	assert(pc);//断言
	char name[20] = { 0 };
	printf("请输入你要查询人的姓名:");
	scanf("%s", name);
	int pos = FindName(pc, name);
	if (pos == -1)
	{
		printf("要查询的联系人不存在\n");
		return;
	}
	else
	{
		//打印列标题
		printf("%-5s\t%-4s\t%-5s\t%-12s\t%15s\n", "姓名", "年龄", "性别", "电话", "地址");
		//打印联系人
			printf("%-5s\t%-4d\t%-5s\t%-12s\t%15s\n",
				pc->data[pos].name,
				pc->data[pos].age,
				pc->data[pos].sex,
				pc->data[pos].tel,
				pc->data[pos].addr);
	}
}

//修改联系人
void ModifyContact(Contact* pc)
{
	assert(pc);//断言
	char name[20] = { 0 };
	printf("请输入你要修改人的姓名:");
	scanf("%s", name);
	int pos = FindName(pc, name);
	if (pos == -1)
	{
		printf("要修改的联系人不存在\n");
		return;
	}
	else
	{
		printf("请输入修改后人的姓名:");
		scanf("%s", pc->data[pos].name);//这里的下标用POS表示,pos接收的是返回的下标
		printf("请输入修改后人的年龄:");
		scanf("%d", &(pc->data[pos].age));
		printf("请输入修改后人的性别:");
		scanf("%s", pc->data[pos].sex);
		printf("请输入修改后人的电话:");
		scanf("%s", pc->data[pos].tel);
		printf("请输入修改后人的地址:");
		scanf("%s", pc->data[pos].addr);
		printf("成功修改联系人\n");
	}
}

//排序联系人
int int_cmp(const void* p1, const void* p2)
{
	//按姓名先后顺序排序--注意要转换成PeopleInfo*类型
	return (strcmp(((PeopleInfo*)p1)->name, ((PeopleInfo*)p2)->name));
}
void SortContact(Contact* pc)
{
    //qsort在我们的高阶指针篇章的回调函数中知道了如何使用及实现,操作对象pc->data,操作元素个数pc->sz,操作每个元素的大小sizeof(PeopleInfo),通过调用int_cmp函数实现排序(默认升序)
	qsort(pc->data, pc->sz, sizeof(PeopleInfo), int_cmp);
	printf("按姓名排序成功\n");
}

//动态版
//清空联系人
void EmptyContact(Contact* pc)
{
	pc->sz = 0;
	pc->capacity = DEFAULT_SZ;
	printf("成功清空联系人\n");
}

//释放空间
void DestroyContact(Contact* pc)
{
	free(pc->data);
	pc->data = NULL;
	pc->capacity = 0;
	pc->sz = 0;
}

四、演示

4.1添加联系人

在这里插入图片描述

在这里插入图片描述

4.2显示联系人

在这里插入图片描述

4.3查询联系人

在这里插入图片描述

4.4修改联系人

在这里插入图片描述

4.5排序联系人

在这里插入图片描述

4.6删除联系人

在这里插入图片描述

4.7清空联系人

在这里插入图片描述

end~

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

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

相关文章

git commit -m时候没有保存package.json等文件

项目场景&#xff1a; 提示&#xff1a;git add . 和 git commit -m "保存" 操作&#xff0c;没有保存package.json等文件。 解决方案&#xff1a; 1.确保 package.json 文件没有被列在 .gitignore 文件中。打开 .gitignore 文件&#xff0c;检查是否有类似于 packa…

数据库运维——备份恢复

数据库备份&#xff0c;数据库为school&#xff0c;素材如下 1.创建student和score表 CREATE TABLE student ( id INT(10) NOT NULL UNIQUE PRIMARY KEY , name VARCHAR(20) NOT NULL , sex VARCHAR(4) , birth YEAR, department VARCHAR(20) , address VARCHAR(…

交换一个整数二进制位的奇数位和偶数位

目录 一、方案一 1.求待操作数的二进制序列 2.创建一个数组存放待操作数的二进制序列 3.交换二进制序列奇偶位 4.输出奇偶位交换之后的二进制序列 5.代码 二、方案二&#xff08;宏的实现&#xff09; 1.求待操作数二进制序列偶数位 2.求待操作数二进制序列奇数位 3.求待…

目标检测——yoloV3案例

目录 数据获取TFrecord文件什么是TFrecord文件将数据转换成TFrecord文件读取TFrecord文件数据处理 模型构建模型训练损失函数的计算正负样本的设定模型训练获取数据集加载模型模型训练 模型预测 数据获取 labellmage使用方法 TFrecord文件 什么是TFrecord文件 将数据转换成T…

python暴力破解wifi密码

python破解WiFi密码 无图形化界面版图形化界面版 刚开始怀着是以为可以自动生成并匹配密码进行破解&#xff0c;然后才知道都需要使用密码本&#xff0c;破解都不知道要猴年马月去了。。。。。但可以研究理解一下代码过程 使用pycharm需要调试一下&#xff0c;比较麻烦&#xf…

【Docker】Docker网络与存储(三)

前言&#xff1a; Docker网络与存储的作用是实现容器之间的通信和数据持久化&#xff0c;以便有效地部署、扩展和管理容器化应用程序。 文章目录 Docker网络桥接网络容器之间的通信 覆盖网络创建一个覆盖网络 Docker存储卷 总结 Docker网络 Docker网络是在容器之间提供通信的机…

速成版-带您一天学完python自动化测试(selenium)

Selenium是一套web网站的程序自动化操作解决方案。我们通过编写自动化程序&#xff0c;使得自动完成浏览器界面的相关操作&#xff0c;除了能够自动化的完成相关操作&#xff0c;还能从web页面获取相关信息&#xff0c;然后通过程序进行分析处理&#xff0c;本质上就是提升从网…

微信小程序的微信一键登录与验证码登录

验证码登录 <template><view class"wx-login"><view class"login-Box"><text class"title">欢迎登录</text><text class"subTitle">再就业男团系统</text><view class"login-Form…

pytorch安装GPU版本 (Cuda12.1)教程: Windows、Mac和Linux系统快速安装指南

&#x1f337;&#x1f341; 博主 libin9iOak带您 Go to New World.✨&#x1f341; &#x1f984; 个人主页——libin9iOak的博客&#x1f390; &#x1f433; 《面试题大全》 文章图文并茂&#x1f995;生动形象&#x1f996;简单易学&#xff01;欢迎大家来踩踩~&#x1f33…

java List的stream().collect()方法实战

文章目录 订单类测试类测试结果 这几天在做银联的银行卡对账时&#xff0c;一开始只使用参考号来确定一笔交易&#xff0c;但是这样是不严谨的&#xff0c;项目经理要求使用商户号、终端号、流水号、批次号、参考号五个数据项来确定唯一性&#xff0c;所以本次list转map是在此背…

分布式调用与高并发处理 Nginx

一、初识Nginx 1.1 Nginx概述 Nginx是一款轻量级的Web服务器、反向代理服务器&#xff0c;由于它的内存占用少&#xff0c;启动极快&#xff0c;高并发能力强&#xff0c;在互联网项目中广泛应用。Nginx 专为性能优化而开发&#xff0c;使用异步非阻塞事件驱动模型。 常见服务…

小程序如何上传商品

​小程序作为一种便捷的电商平台&#xff0c;上传商品是非常重要的一步。本文将为你提供一个完整的小程序上传商品教程&#xff0c;帮助你轻松上架自己的商品。 一、进入商品管理页面 在个人中心点击管理入口&#xff0c;然后找到“商品管理”菜单并点击。 2. 点击“添加商品…

【C++初阶】容器适配器模拟实现栈和队列(附源码)

一.容器适配器 其实在使用模板时&#xff0c;我们不仅可以使用类模板&#xff0c;还可以使用容器模板&#xff0c;这就是一个容器适配器&#xff0c;我们可任意给模板实例化不同的容器&#xff0c;然后就可以使用容器里的接口。 template<class T,class Containers> 我们…

轮播图添加删除

轮播图页面和对话框搭建 页面简单布局 <template><div id"banner"><el-space direction"vertical" :size"20" style"width: 100%"><h1>轮播图管理</h1><div style"text-align: right"&g…

【论文阅读】DQnet: Cross-Model Detail Querying for Camouflaged Object Detection

DQnet: Cross-Model Detail Querying for Camouflaged Object Detection DQnet&#xff1a;伪装目标检测中的跨模型细节查询 论文地址&#xff1a;https://arxiv.org/abs/2212.08296 这篇文章提出了一个交叉模型框架&#xff08;CNN-Transformer并行&#xff09;来检测伪装目…

Cocoapods 集成与初始化 - swift

基于新的 swift 工程集成 cocoapods,操作过程与 object-c 类似, 如下操作基于已成功安装 cocoapods 的基础之上; 首先,终端访问到工程根目录下 cd xxx工程文件夹路径xxx 其次,创建 Podfile 文件 vim Podfile 再其次,创建成功后工程根目录下会得到一个 Podfile 文件,通过终…

MySQL事务机制、导入导出、数据表设计案例(六)

目录 一、数据库事务机制1.1 undo和redo日志1.2 开启事务、提交事务、回滚事务1.3 事务的ACID属性1.4 事务的并发性1.4.1 业务案例1&#xff1a;抢车票1.4.2 业务案例2&#xff1a;转账1.4.3 业务案例3 电商涨价1.4.4 事务的序列化 二、数据导出与导入2.1 SQL文件的导出与导入2…

【操作教程】在EasyCVR平台实现播放MP4视频的两种方法

目前EasyCVR平台可支持国标GB28181、RTSP/Onvif、RTMP、海康Ehome、SDK等方式接入&#xff0c;这些接入方式主要是针对设备或视频流的接入。在有些项目现场也会遇到播放MP4视频文件的需求&#xff0c;今天我们来介绍下&#xff0c;如何在EasyCVR平台实现MP4视频文件的播放&…

vue-element-template管理模板(一)

模板下载 选择分支&#xff1a;https://github.com/PanJiaChen/vue-admin-template/tree/permission-control 端口修改、关闭Eslint 修改vue.config.js文件&#xff08;用放大镜搜索“9528”定位文件&#xff09; const port 9528 lintOnSave: false国际化设置 import lo…

PHP8知识详解:PHP是什么?

PHP是什么&#xff1f; 杨泽业从下面几点为你讲清楚什么是PHP。 1、PHP最开始是Personal Home Page&#xff08;个人主页&#xff09;的缩写&#xff0c;已经正式更名为 “PHP: Hypertext Preprocessor”&#xff0c;超文本预处理器的字母缩写。 2、PHP是一种被广泛应用的、…