C顺序表:通讯录

目录

前言

通讯录数据结构

通讯录初始化 

查找名字

增加联系人

删除联系人

展示所有联系人

查找联系人

修改信息

销毁通讯录

完整通讯录代码


前言

数据结构中的顺序表如果已经学会了,那么我们就可以基于顺序表来完成一个通讯录了

通讯录其实我们使用前面学习过的顺序表就能完成不过,相比较来说,前面的顺序表就是个整型数组,但通讯录就是一个多信息的自定义类型了

如果没了解过顺序表的可以看看我前篇博客

C数据结构:顺序表-CSDN博客

下面直接来开始完成我们的通讯录吧

通讯录数据结构

typedef struct PersonInfo
{
	char name[NAME_MAX];
	char sex[SEX_MAX];
	int age;
	char tel[TEL_MAX];
	char addr[ADDR_MAX];
}PeoInfo;

typedef PeoInfo SLDataType;
//typedef int SLDataType;

typedef struct SeqList
{
    SLDataType* a;
    int size;     // 有效数据个数
    int capacity; // 空间容量
}SL;

通讯里结构体里定义了五个成员,名字、性别、年龄、电话、地址

数组大小使用了宏定义,因为有需要更改的时候就比较方便,不需要一个个去更改

下面就开始通讯录的实现吧

如果文件中有顺序表的.c文件,请务必屏蔽以下函数,否则会引起报错

 

 

1. SLPrint函数中含有 %d,%d是整型的占位符,如果我们需要打印自定义类型是不能使用%d占位符的

2. SLFind函数中if的判断条件 ps->a[i] == x这个有错误,我们的a数组的类型是个自定义类型,该类型里含有5个成员,怎么能直接让两个自定义类型直接比较呢?

通讯录初始化 

void InitContact(contact* con)
{
	SLInit(con);
}

初始化一个联系人就和初始化一个顺序表一样,所以直接使用顺序表的函数对里面的参数con进行初始化即可 

查找名字

int FindByName(contact* con, char name[])
{
	assert(con);

	for (int i = 0; i < con->size; i++)
	{
		if (strcmp(con->a[i].name, name) == 0)
		{
			return i;
		}
	}
	return -1;
}

为什么要先写查找名字呢?

因为我们后面删除联系人、查找联系人、修改联系人都会使用到这个模板,如果都按一个模板来写会显得代码很冗余,并且浪费时间,所以我们直接写一个函数就可以有效的解决这个问题

我们直接遍历整个联系人a数组里面的名字,当名字匹配的时候,我们就返回它的下标,否则出了循环之后说明没找到名字,则返回-1

我们不能直接写

con->a[i].name == name作为if语句的条件

因为这个name是个char类型的数组名,而数组名是地址,用地址来比较是得不出答案的,所以需要借助到string.h里的strcmp函数 

对string.h库函数有兴趣的可以看看我前面的博客 

ctype.h的了解string.h库函数中各个函数的使用和模拟实现-CSDN博客

增加联系人

void AddContact(contact* con)
{
	assert(con);

	PeoInfo c;
	printf("请输入姓名:>");
	scanf("%s", c.name);
	printf("请输入性别:>");
	scanf("%s", c.sex);
	printf("请输入年龄:>");
	scanf("%d", &c.age);
	printf("请输入电话:>");
	scanf("%s", c.tel);
	printf("请输入地址:>");
	scanf("%s", c.addr);

	SLPushBack(con, c);
}
void SLPushBack(SL* ps, SLDataType x)
{
	assert(ps);

	SLCheckCapacity(ps); //检查数组大小是否足够
	ps->a[ps->size] = x;
	ps->size++;
}

 先是定义了一个通讯录c变量,并把我们需要增加的联系人的信息先暂时放到c中

最后使用顺序表里的SLPushBack函数将这些信息放到我们的通讯录数组中即可

删除联系人

void DelContact(contact* con)
{
	assert(con);

	char name[NAME_MAX];
	printf("请输入要删除的姓名:>");
	scanf("%s", name);
	int pos = FindByName(con, name);
	if (pos < 0)
	{
		printf("要删除的用户不存在!\n");
		return;
	}
	SLErase(con, pos);
	printf("删除成功\n");
}
void SLErase(SL* ps, int pos)
{
	assert(ps);
	assert(pos <= ps->size && pos >= 0);
	assert(ps->size > 0);

	for (int i = pos; i < ps->size - 1; i++)
	{
		ps->a[i] = ps->a[i + 1];
	}
	ps->size--;
}

先定义了一个name数组接收我们要删除的人的名字,然后使用我们前面写到的FindByName找到这个名字的下标,最后使用SLErase函数删除掉通讯录数组这个下标所在的位置即可

展示所有联系人

void ShowContact(contact* con)
{
	assert(con);

	//打印表头
	printf("姓名\t性别\t年龄\t电话\t地址\n");
	for (int i = 0; i < con->size; i++)
	{
		printf("%s\t%s\t%d\t%s\t%s\n", con->a[i].name,
			con->a[i].sex,
			con->a[i].age,
			con->a[i].tel,
			con->a[i].addr
		);
	}
}

展示这一步就是给使用者看的,为了美观对齐所以在每一个信息的后面加了一个\t

最后用for循环遍历通讯录数组打印所有的信息即可

查找联系人

void FindContact(contact* con)
{
	assert(con);

	char name[NAME_MAX];
	printf("请输入要查找的姓名:>");
	scanf("%s", name);
	int pos = FindByName(con, name);
	if (pos < 0)
	{
		printf("查找的用户不存在!\n");
		return;
	}
	printf("查找成功\n");
	printf("%s\t%s\t%d\t%s\t%s\t", con->a[pos].name,
		con->a[pos].sex,
		con->a[pos].age,
		con->a[pos].tel,
		con->a[pos].addr
	);
}

 还是一样先找到名字所在通讯录数组的下标,如果能找到说明联系人存在,利用下标打印出该人的信息即可

修改信息

void ModifyContact(contact* con)
{
	assert(con);

	char name[NAME_MAX];
	printf("请输入要修改的姓名:>");
	scanf("%s", name);
	int pos = FindByName(con, name);
	if (pos < 0)
	{
		printf("查找的用户不存在!\n");
		return;
	}
	
	printf("请输入姓名:>");
	scanf("%s", con->a[pos].name);
	printf("请输入性别:>");
	scanf("%s", con->a[pos].sex);
	printf("请输入年龄:>");
	scanf("%d", &con->a[pos].age);
	printf("请输入电话:>");
	scanf("%s", con->a[pos].tel);
	printf("请输入地址:>");
	scanf("%s", con->a[pos].addr);
	printf("修改成功\n");
}

也是一样先查找该名字所在通讯录数组的下标,然后重新使用scanf输入该下标的所有信息即可 

销毁通讯录

void DestroyContact(contact* con)
{
	assert(con);

	SLDestroy(con);
}
void SLDestroy(SL* ps)
{
	assert(ps);

	if (ps->a)
	{
		free(ps->a);
	}
	ps->a = NULL;
	ps->capacity = ps->size = 0;
}

销毁直接用顺序表中的SLDestroy实现即可

完整通讯录代码

#define _CRT_SECURE_NO_WARNINGS 1

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

#define NAME_MAX 100
#define SEX_MAX 4
#define TEL_MAX 11
#define ADDR_MAX 100

//前置声明
typedef struct SeqList contact;

//用户数据
typedef struct PersonInfo
{
	char name[NAME_MAX];
	char sex[SEX_MAX];
	int age;
	char tel[TEL_MAX];
	char addr[ADDR_MAX];
}PeoInfo;

//初始化通讯录
void InitContact(contact* con);

//添加通讯录数据
void AddContact(contact* con);

//删除通讯录数据
void DelContact(contact* con);

//展示通讯录数据
void ShowContact(contact* con);

//查找通讯录数据
void FindContact(contact* con);

//修改通讯录数据
void ModifyContact(contact* con);

//销毁通讯录数据
void DestroyContact(contact* con);

typedef PeoInfo SLDataType;
//typedef int SLDataType;

// 动态顺序表 -- 按需申请
typedef struct SeqList
{
    SLDataType* a;
    int size;     // 有效数据个数
    int capacity; // 空间容量
}SL;

//初始化和销毁
void SLInit(SL* ps);
void SLDestroy(SL* ps);
void SLPrint(SL* ps);
//扩容
void SLCheckCapacity(SL* ps);

//头部插入删除 / 尾部插入删除
void SLPushBack(SL* ps, SLDataType x);
void SLPopBack(SL* ps);
void SLPushFront(SL* ps, SLDataType x);
void SLPopFront(SL* ps);

//指定位置之前插入/删除数据
void SLInsert(SL* ps, int pos, SLDataType x);
void SLErase(SL* ps, int pos);
int SLFind(SL* ps, SLDataType x);

void SLInit(SL* ps)
{
	assert(ps);

	ps->a = NULL;
	ps->capacity = ps->size = 0;
}

void SLDestroy(SL* ps)
{
	assert(ps);

	if (ps->a)
	{
		free(ps->a);
	}
	ps->a = NULL;
	ps->capacity = ps->size = 0;
}

//void SLPrint(SL* ps)
//{
//	assert(ps);
//
//	for (int i = 0; i < ps->size; i++)
//	{
//		printf("%d ", ps->a[i]);
//	}
//	printf("\n");
//}

void SLCheckCapacity(SL* ps)
{
	assert(ps);

	if (ps->capacity == 0)
	{
		ps->a = (SLDataType*)malloc(sizeof(SLDataType) * 4);
		ps->capacity = 4;
	}

	if (ps->capacity == ps->size && ps->capacity != 0)
	{
		//定义tmp接收防止扩容失败原数组被覆盖
		SLDataType* tmp = (SLDataType*)realloc(ps->a, ps->capacity * 2 * sizeof(SLDataType));
		if (tmp == NULL)
		{
			perror("realloc fail!\n");
			return;
		}
		//扩容成功
		ps->a = tmp;
		ps->capacity *= 2;
	}
}

void SLPushBack(SL* ps, SLDataType x)
{
	assert(ps);

	SLCheckCapacity(ps);
	ps->a[ps->size] = x;
	ps->size++;
}

void SLPopBack(SL* ps)
{
	assert(ps);
	assert(ps->size > 0);

	ps->size--;
}

void SLPushFront(SL* ps, SLDataType x)
{
	assert(ps);

	SLCheckCapacity(ps);

	for (int i = ps->size - 1; i >= 0; i--)
	{
		ps->a[i + 1] = ps->a[i];
	}
	ps->a[0] = x;
	ps->size++;
}

void SLPopFront(SL* ps)
{
	assert(ps);
	assert(ps->size > 0);

	for (int i = 0; i < ps->size - 1; i++)
	{
		ps->a[i] = ps->a[i + 1];
	}
	ps->size--;
}

void SLInsert(SL* ps, int pos, SLDataType x)
{
	assert(ps);
	assert(pos <= ps->size && pos >= 0);

	SLCheckCapacity(ps);

	for (int i = ps->size; i >= pos; i--)
	{
		ps->a[i + 1] = ps->a[i];
	}
	ps->a[pos] = x;
	ps->size++;
}

void SLErase(SL* ps, int pos)
{
	assert(ps);
	assert(pos <= ps->size && pos >= 0);
	assert(ps->size > 0);

	for (int i = pos; i < ps->size - 1; i++)
	{
		ps->a[i] = ps->a[i + 1];
	}
	ps->size--;
}

//int SLFind(SL* ps, SLDataType x)
//{
//	assert(ps);
//	
//	for (int i = 0; i < ps->size; i++)
//	{
//		if (ps->a[i] == x)
//		{
//			return i;
//		}
//	}
//
//	return -1;
//}

void InitContact(contact* con)
{
	SLInit(con);
}

void AddContact(contact* con)
{
	assert(con);

	PeoInfo c;
	printf("请输入姓名:>");
	scanf("%s", c.name);
	printf("请输入性别:>");
	scanf("%s", c.sex);
	printf("请输入年龄:>");
	scanf("%d", &c.age);
	printf("请输入电话:>");
	scanf("%s", c.tel);
	printf("请输入地址:>");
	scanf("%s", c.addr);

	SLPushBack(con, c);
}

int FindByName(contact* con, char name[])
{
	assert(con);

	for (int i = 0; i < con->size; i++)
	{
		if (strcmp(con->a[i].name, name) == 0)
		{
			return i;
		}
	}
	return -1;
}

void DelContact(contact* con)
{
	assert(con);

	char name[NAME_MAX];
	printf("请输入要删除的姓名:>");
	scanf("%s", name);
	int pos = FindByName(con, name);
	if (pos < 0)
	{
		printf("要删除的用户不存在!\n");
		return;
	}
	SLErase(con, pos);
	printf("删除成功\n");
}

void ShowContact(contact* con)
{
	assert(con);

	//打印表头
	printf("姓名\t性别\t年龄\t电话\t地址\n");
	for (int i = 0; i < con->size; i++)
	{
		printf("%s\t%s\t%d\t%s\t%s\n", con->a[i].name,
			con->a[i].sex,
			con->a[i].age,
			con->a[i].tel,
			con->a[i].addr
		);
	}
}

void FindContact(contact* con)
{
	assert(con);

	char name[NAME_MAX];
	printf("请输入要查找的姓名:>");
	scanf("%s", name);
	int pos = FindByName(con, name);
	if (pos < 0)
	{
		printf("查找的用户不存在!\n");
		return;
	}
	printf("查找成功\n");
	printf("%s\t%s\t%d\t%s\t%s\t", con->a[pos].name,
		con->a[pos].sex,
		con->a[pos].age,
		con->a[pos].tel,
		con->a[pos].addr
	);
}

void ModifyContact(contact* con)
{
	assert(con);

	char name[NAME_MAX];
	printf("请输入要修改的姓名:>");
	scanf("%s", name);
	int pos = FindByName(con, name);
	if (pos < 0)
	{
		printf("查找的用户不存在!\n");
		return;
	}
	
	printf("请输入姓名:>");
	scanf("%s", con->a[pos].name);
	printf("请输入性别:>");
	scanf("%s", con->a[pos].sex);
	printf("请输入年龄:>");
	scanf("%d", &con->a[pos].age);
	printf("请输入电话:>");
	scanf("%s", con->a[pos].tel);
	printf("请输入地址:>");
	scanf("%s", con->a[pos].addr);
	printf("修改成功\n");
}

void DestroyContact(contact* con)
{
	assert(con);

	SLDestroy(con);
}

void Test2()
{
	contact c;
	InitContact(&c);
	AddContact(&c);
	AddContact(&c);
	ShowContact(&c);
	//DelContact(&c);
	ModifyContact(&c);
	ShowContact(&c);
	FindContact(&c);
	DestroyContact(&c);
}

int main()
{
	//Test1();
	Test2();
	return 0;
}

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

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

相关文章

项目运维方案资料-(word原件)31页

1. 文档介绍 2. 人员与责任 3. 运维过程内容 4. 运维资源 5. 运维服务规划保障 6. 事件处置 7. 质量改进 8. 运维边界及内容 软件开发管理全套资料获取方式①&#xff1a;点我获取 获取方式②&#xff1a;本文末个人名片直接获取。

SpringBoot快速入门笔记(5)

文章目录 一、elemetnUI1、main.js2、App.vue3、fontAwesome 一、elemetnUI 开源前端框架&#xff0c;安装 npm i element-ui -S 建议查看官方文档 Element组件&#xff0c;这里是Vue2搭配elementUI&#xff0c;如果是vue3就搭配elementPlus&#xff0c;这里初学就以Vue2为例子…

Matlab 基础语法 小结

input x input(prompt) # input digit str1 input(prompt,s) # input string执行图像处理任务 require Image Processing Toolbox Image Processing Toolbox™ provides a comprehensive set of reference-standard algorithms and workflow apps for image processing, a…

农业气象站的工作原理

TH-NQ8农田小气候监测站是一种专门用于监测农田内小范围气候状况的设备&#xff0c;其作用主要体现在以下几个方面&#xff1a; 实时监测与记录&#xff1a;通过配备的多种传感器&#xff0c;能够实时监测和记录农田内不同位置的气温、湿度、风速、风向、降雨量等气象要素的变化…

Android 9.0 framework层实现app默认全屏显示

1.前言 在9.0的系统rom产品定制化开发中,在对于第三方app全屏显示的功能需求开发中,需要默认app全屏显示,针对这一个要求,就需要在系统启动app 的过程中,在绘制app阶段就设置全屏属性,接下来就实现这个功能 效果图如下: 2.framework层实现app默认全屏显示的核心类 fram…

nginx配置实例-动静分离

目录 一、相关概念 1.1动静分离概念 1.2动静分离的两种实现方法 二、实例配置 2.1 准备工作&#xff1a;在linux系统中准备静态资源&#xff0c;方便后面做测试 2.2 修改nginx配置文件 2.3 在浏览器测试 一、相关概念 1.1动静分离概念 将动态请求跟静态请求分开&#xf…

下半年跨境电商全球市场持续扩大,掌握测评自养号技术将迎来新机遇

2024年跨境电商在下半年有望继续保持稳健增长&#xff0c;市场将更加国际化、便捷化和智能化&#xff0c;为消费者和卖家带来更多机遇和发展空间。 全球化市场持续扩大&#xff0c;随着全球市场的进一步开放和互联网的普及&#xff0c;跨境电商将继续拓展到更多的国家和地区。消…

使用aspose相关包将excel转成pdf 并导出

SpringBoot 项目 基于aspose相关jar包 将excel 转换成pdf 导出 1、依赖的jar包 &#xff0c; jar获取链接 aspose相关三方jar &#xff0c;下载解压后,在项目路径下建一个libs包&#xff0c;然后将下图两个jar 拷贝至刚新建的libs目录中 2、pom.xml中加入maven引入 <depend…

通用开发技能系列:Scrum、Kanban等敏捷管理策略

云原生学习路线导航页&#xff08;持续更新中&#xff09; 本文是 通用开发技能系列 文章&#xff0c;主要对编程通用技能 Scrum、Kanban等敏捷管理策略 进行学习 1.什么是敏捷开发 敏捷是一个描述软件开发方法的术语&#xff0c;它强调增量交付、团队协作、持续规划和持续学习…

具身智能机器人实现新里程碑!新型3D世界模型问世

随着人工智能技术的不断进步&#xff0c;视觉-语言-动作&#xff08;VLA&#xff09;模型在机器人控制、自动驾驶、智能助手等领域展现出了广阔的应用前景。这类模型能够将视觉、语言、动作等多模态信息进行融合&#xff0c;实现从感知到决策的端到端学习。然而&#xff0c;现有…

【Python基础】生成器

文章目录 [toc]什么是生成器生成器示例生成器工作流程生成器表达式send()方法和close()方法send()方法close()方法 个人主页&#xff1a;丷从心. 系列专栏&#xff1a;Python基础 学习指南&#xff1a;Python学习指南 什么是生成器 在Python中&#xff0c;使用生成器可以很方…

Longan Pi 3H 开发板体验

Longan Pi 3H 开发板体验 开箱内容 打开包装&#xff0c;你可以看到以下物品 一个Longan Pi 3H盒子Longan Pi 3H开发板 产品基本介绍 Longan Pi 3H 是基于 Longan Module 3H 核心板的 ARM Linux 开发板&#xff0c;以 H618 (Quad core ARM Cortex-A531.5Ghz , 64-bit) 为主控…

合并主分支到子分支

参考&#xff1a;【Git】合并分支出现 Please enter a commit message to explain why this merge is necessary.-CSDN博客 git 如何将主分支(master)合并到子分支上_git 将主分支合并到子分支-CSDN博客 1、先切换到主分支master git checkout master 2、把主分支代码拉到本地…

小程序实现订阅功能和测试发送订阅信息

现在一次性订阅是只能用户点一次才能发送一次&#xff0c;而针对长期模板只有规定的几种类目政务、民生、交通等等的才可以&#xff0c;所以说感觉这功能其实已经不是很适合使用了&#xff0c;只适合一些特别的场景才可以使用。 地址&#xff1a;https://developers.weixin.qq…

【排列回溯】Leetcode 46. 全排列 47. 全排列 II

【排列回溯】Leetcode 46. 全排列 47. 全排列 II 46 全排列——used数组上下层保证不取重复的即可47. 全排列 II——used去重上下层&#xff0c;再去重本层重复元素 46 全排列——used数组上下层保证不取重复的即可 ---------------&#x1f388;&#x1f388;题目链接&#x…

2024年面试AI编译器岗经验总结

面试经历: 面试中必备的知识: 1.用C++实现一个卷积 (图解)一步一步使用CPP实现深度学习中的卷积 - GiantPandaCVGiantPandaCVhttp://giantpandacv.com/academic/%E7%AE%97%E6%B3%95%E7%A7%91%E6%99%AE/%E5%B0%BD%E8%A7%88%E5%8D%B7%E7%A7%AF%E7%A5%9E%E7%BB%8F%E7%BD%91%E…

Springboot引入swagger

讲在前面&#xff1a;在spring引入swagger时&#xff0c;由于使用的JDK、Spring、swagger 的版本不匹配&#xff0c;导致启动报错&#xff0c;一直存在版本依赖问题。所以在此声明清楚使用版本。JDK 1.8、Spring boot 2.6.13、 Swagger 2.9.2。 引入maven依赖 <dependency&…

Mysql【索引覆盖、索引下推、索引合并、索引跳跃】介绍

索引覆盖、索引下推、索引合并、索引跳跃都是Mysql对索引的优化手段&#xff0c;它们的思想就是尽量让查询数据走索引&#xff0c;那它们有什么区别呢&#xff1f; 一、首先介绍一下MySQL体系结构 上图来自MySQL官方文档。 通常把MySQL从上至下分为以下几层&#xff1a; MySQ…

备考ICA----Istio实验18---单集群中部署多个Istio控制面

备考ICA----Istio实验18—单集群中部署多个Istio控制面 单个 Kubernetes 控制面以及多个 Istio 控制面和多个网格。通过 Kubernetes 命名空间和 RBAC 实现软多租户业务隔离。 1. 环境准备 1.1 创建2个命名空间 kubectl create ns usergroup-1 kubectl label ns usergroup-…

外包干了6天,技术明显进步

先说一下自己的情况&#xff0c;本科生&#xff0c;2019年我通过校招踏入了南京一家软件公司&#xff0c;开始了我的职业生涯。那时的我&#xff0c;满怀热血和憧憬&#xff0c;期待着在这个行业中闯出一片天地。然而&#xff0c;随着时间的推移&#xff0c;我发现自己逐渐陷入…