通讯录(静态版)

news2025/2/12 13:56:32

通讯录(静态版)

通讯录无非就是实现以下功能:[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-EkYPr93F-1691752059500)(C:\Users\30539\AppData\Roaming\Typora\typora-user-images\image-20230810225856596.png)]

1.前言

首先要知道一个人要包含哪些信息,这里就以(姓名,年龄,性别,电话号码,地址)为例,这些信息中,年龄和其他四项是不同的数据类型,其他四项可以使用cha类型的数组来进行表示,所以可以将这五种信息放在一个结构体里,声明一个名为“联系人”的结构体:

typedef struct PeoInfo
{
	char name[MAX_NAME];
	int age;
	char sex[MAX_SEX];
	char tele[MAX_TELE];
	char addr[MAX_ADDR];
}PeoInfo;

注意:这里数组内的常量最好是定义成宏,这样后续修改起来就很方便了。

这里typedef类型重命名一下比较方便。

当然这只是构建了一个联系人需要包含的信息,但是通讯录中应该包含不止一个人的信息,所以还需要创建一个联系人类型的数组:

PeoInfo data[100];这里就假设最多只能存下100个联系人。

但是这样定义是否有一些缺陷呢?那就是假设我们存储了100个人,还想接着存储联系人,但是由于此时并没有变量来记录通讯录中的联系人的个数,就会产生容量不足的问题。所以,需要一个变量来记录存储的联系人的个数。那我们不妨将这两部分放到结构体里:定义一个通讯录结构体。

typedef struct Contact
{
	PeoInfo data[MAX];
	int sz;
}Contact;

现在通讯录定义好了,那么sz此时是默认的值,这个值是不可控的,所以需要设计一个初始化函数,对创建的通讯录变量中的内容置为0:

Contact Con;//定义一个通讯录变量
void InitCon(Contact* pc)//初始化
{
	assert(pc);
	memset(pc->data, 0, sizeof(pc->data));
	pc->sz = 0;
}

注意:这里函数的参数部分最好是设计成结构体指针类型,比较节约内存资源,这里也是在前面讲过的内容了。后面的关于通讯录的相关函数的参数部分都设计成了结构体指针类型。

初始化之后,就可以开始设计对通讯录进行操作的函数了。

2.增加联系人

增加联系人函数

结构体在经过初始化之后,sz的值变成了0,而0刚好可以作为通讯录中的下一个元素的下标。此时通讯录中没有联系人,所以第一个联系人的下标就是sz,后续推理也是成立的。

注意:

  1. 函数参数是结构体指针类型,此时一定最好要判断该指针是否为空,这是一个良好的习惯。
  2. 增加联系人之后,一定要更新sz变量
void AddCon(Contact* pc)//添加联系人
{
	assert(pc);//pc不能为空
	printf("请输入你要添加的人的姓名:\n");
	scanf("%s", pc->data[pc->sz].name);
	printf("请输入你要添加的人的年龄:\n");
	scanf("%d", &(pc->data[pc->sz].age));
	printf("请输入你要添加的人的性别:\n");
	scanf("%s", pc->data[pc->sz].sex);
	printf("请输入你要添加的人的电话:\n");
	scanf("%s", pc->data[pc->sz].tele);
	printf("请输入你要添加的人的住址:\n");
	scanf("%s", pc->data[pc->sz].addr);
	printf("添加成功!\n");
	pc->sz++;
}

根据姓名查找函数的设计FindByName函数:pos可以先设置初始值为-1,假如查找到了对应的联系人,就将下标赋值给pos变量,并返回pos,最后假如没找到该联系人,也直接返回pos,比较方便。

int  FindByName(const Contact* pc, char* name)
{
	assert(pc);
	int pos = -1;
	for (int i = 0; i < pc->sz; i++)
	{
		if (strcmp(pc->data[i].name, name) == 0)
		{
			pos = i;
			break;
		}
	}
	return pos;
}

3.删除联系人

删除联系人函数

同理的,这里也要判断pc指针是否为空,同时在设计删除联系人函数的时候,也可以加一个联系人个数是否为0的判断。

我这里是按着名字来查找的联系人,当然也可以用其他信息来进行查找。

void DeleCon(Contact* pc)//删除联系人
{
	assert(pc);
	assert(pc->sz);
	printf("请输入你要删除的人的姓名:\n");
	char name[MAX_NAME];
	scanf("%s", name);
	int pos = FindByName(pc, name);
	if (pos == -1)
	{
		printf("该人不存在!\n");
		return;
	}
	else
	{
		memmove(pc->data + pos, pc->data + pos + 1, sizeof(PeoInfo) * (pc->sz - pos - 1));
	}
	pc->sz--;
}

注意这里的按着名字查找封装成一个函数是比较高效的,后续查找联系人的时候也会用到的。

4.查找联系人

查找联系人函数:(这里就可以调用FindBbyName函数,更高效)

void FindCon(const Contact* pc)//查找联系人
{
	assert(pc);
	assert(pc->sz);
	printf("请输入你要查找的人的姓名:\n");
	char tmp[MAX_NAME] = { 0 };
	scanf("%s", tmp);
	int pos = FindByName(pc, tmp);
	if (pos == -1)
	{
		printf("要查找的人不存在!\n");
		return;
	}
	else
	{
		printf("这是查找到的联系人的信息:\n");
		printf("%-10s\t%-5s\t%-5s\t%-12s\t%-20s\n", "姓名", "年龄", "性别", "电话", "地址");
		printf("%-10s\t%-5d\t%-5s\t%-12s\t%-20s",
			pc->data[pos].name,
			pc->data[pos].age,
			pc->data[pos].sex,
			pc->data[pos].tele,
			pc->data[pos].addr);
	}
	printf("\n");
}

这里要注意以下这里的printf打印的细节,就以 printf("%-10s\t%-5s\t%-5s\t%-12s\t%-20s\n", "姓名", "年龄", "性别", "电话", "地址");为例,后面的“姓名”,“年龄”等这些内容,实际上都是字符串,都要以%s的形式打印,要想控制好格式,可以在%和S之间,加字段宽度(控制字段宽度),同时加上一个减号(让内容左对齐),并且在一个信息打印之后加一个'\t'也能更美观,配合换行的使用,即可变得比较美观。

5.修改联系人

修改联系人函数

同样的这里要修改联系人,首先要查找到要修改的联系人的下标,这里也可以复用FindByName函数进行姓名查找。

void ModiCon(Contact* pc)//修改联系人
{
	assert(pc);
	assert(pc->sz);
	printf("请输入你要修改的人的姓名:\n");
	char tmp[MAX_NAME] = { 0 };
	scanf("%s", tmp);
	int pos = FindByName(pc, tmp);
	if (pos == -1)
	{
		printf("要修改的人不存在!\n");
		return;
	}
	else
	{
		printf("请输入你要修改的人的姓名:\n");
		scanf("%s", pc->data[pos].name);
		printf("请输入你要修改的人的年龄:\n");
		scanf("%d", &(pc->data[pos].age));
		printf("请输入你要修改的人的性别:\n");
		scanf("%s", pc->data[pos].sex);
		printf("请输入你要修改的人的电话:\n");
		scanf("%s", pc->data[pos].tele);
		printf("请输入你要修改的人的住址:\n");
		scanf("%s", pc->data[pos].addr);
		printf("修改成功!\n");
	}
}

6.显示联系人

显示通讯录函数

这里在显示通讯录的人的时候,可以模仿一下前面的printf的使用方法,显示的时候使用 \t等符号,展示的比较清楚。

void ShowCon(const Contact* pc)//打印联系人
{
	assert(pc);
	printf("\n%-10s\t%-5s\t%-5s\t%-12s\t%-20s\n", "姓名", "年龄", "性别", "电话", "地址");
	for (int i = 0; i < pc->sz; i++)
	{
		printf("%-10s\t%-5d\t%-5s\t%-12s\t%-20s\n",
			pc->data[i].name,
			pc->data[i].age,
			pc->data[i].sex,
			pc->data[i].tele,
			pc->data[i].addr);
	}
}

7.排序联系人

排序联系人函数:

在对联系人进行排序的时候,我们可以自己制定排序的标准,例如:按着姓名排序呢?还是按着年龄来排序。这里就可以使用我们之前讲解过的qsort函数了。(qsort函数忘记了就去看看指针进阶里的文章里对qsort函数的讲解)qsort函数的最后一个参数是一个规定排序方法的函数名。这里针对姓名和年龄,可以写出两种关于排序方式的函数:

通过姓名排序

int compare_name(const void* p1, const void* p2)
{
	assert(p1);
	assert(p2);
	while (*(char*)p1 == *(char*)p2)
	{
		if (*(char*)p1 == '\0')
			return 0;
		p1 = (char*)p1 + 1;
		p2 = (char*)p2 + 1;
	}
	return (*(char*)p1) - (*(char*)p2);
}

通过年龄排序

int compare_age(const void* p1, const void* p2)
{
	assert(p1);
	assert(p2);
	return (*(int*)p1) - (*(int*)p2);
}

排序函数便可以这样设计:

void SortCon(Contact* pc)//对通讯录进行排序
{
	assert(pc);
	assert(pc->sz);
	int input = 0;
	printf("1.姓名\n");
	printf("2.年龄\n");
	printf("请输入排序方式:\n");
	scanf("%d", &input);
	if (input == 1)
	{
		qsort(pc->data,pc->sz,sizeof(PeoInfo),compare_name);
	}
	else
	{
		qsort(pc->data,pc->sz,sizeof(PeoInfo),compare_age);
	}
}

这里就是简单调用的一下qsort函数,自己设计了一下比较函数。

8.完结

通讯录(静态版)的全部内容就到这里啦,若有不足,欢迎评论区指正,下期见!

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

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

相关文章

ssh-keygen 做好免密登录后不生效

免密说明 通常情况下&#xff0c;我们ssh到其他服务器需要知道服务器的用户名和密码。对于需要经常登录的服务器每次都输入密码比较麻烦&#xff0c;因此我们可以在两台服务器上做免密登录&#xff0c;即在A服务器可以免密登录B服务器。 在A服务器上登录B服务器时&#xff0c;…

29 | 广州美食店铺数据分析

广州美食店铺数据分析 一、数据分析项目MVP加/价值主张宣言 随着经济的快速发展以及新媒体的兴起,美食攻略、美食探店等一系列东西进入大众的眼球,而人们也会在各大平台中查找美食推荐,因此本项目做的美食店铺数据分析也是带有可行性的。首先通过对广东省的各市美食店铺数量…

Qt扫盲-Qt Model/View 理论总结 [上篇]

Qt Model/View 理论总结 [上篇] 一、概述1.model / view 架构2. Model3. View4. Delegate5. 排序6. 快捷类 二、使用model/view1. Qt包含两种 model2. 在现有 model 中使用 view 三、Model 类1. 基本概念1.model 索引2. 行和列2. item 的父 item3. Item roles4. 总结 2. 使用mo…

小程序生成App:轻量低门槛的开发方式

小程序生成App可以成为一种轻量低门槛的开发App的方式&#xff0c;但是需要根据具体情况进行选择。如果应用需要处理大量数据或需要进行复杂计算&#xff0c;或者需要实现原生特有的功能或交互效果&#xff0c;可能需要选择其他开发方式。 在文章开始之前&#xff0c;我们看看目…

优维产品最佳实践第4期:如何在海量日志中捞到你要的关键字?

优维产品最佳实践第4期&#xff1a;如何在海量日志中“捞“到你要的关键字&#xff1f; 日志记录了软件系统的生命线&#xff0c;为我们提供了故障排查和性能优化的关键线索。 本期EasyOps产品使用最佳实践&#xff0c;我们将为您揭晓&#xff1a; 如何监控日志的关键字&#x…

c51单片机串口通信(中断方式接收数据)(单片机--单片机通信)示例代码 附proteus图

单片机一般采用中断方式接受数据&#xff0c;这样便于及时处理 #include "reg51.h" #include "myheader.h" #define uchar unsigned char int szc[10]{0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90}; int bufferc[6]{0}; int sza[6]{0x01,0x02,0x0…

【论文阅读】基于深度学习的时序预测——LSFT-Linear

系列文章链接 论文一&#xff1a;2020 Informer&#xff1a;长时序数据预测 论文二&#xff1a;2021 Autoformer&#xff1a;长序列数据预测 论文三&#xff1a;2022 FEDformer&#xff1a;长序列数据预测 论文四&#xff1a;2022 Non-Stationary Transformers&#xff1a;非平…

allegro中不可选时,如何对find进行可选操作

allegro出现不可选时&#xff0c;只能尝试其他单一的操作&#xff0c;但这样效率不高&#xff1b;可以通过菜单栏Display下拉菜单点击Element&#xff0c;即可实现FIND下选择需要调整的选项。

【PCL】激光雷达常用传统感知算法学习

&#x1f60f;★,:.☆(&#xffe3;▽&#xffe3;)/$:.★ &#x1f60f; 这篇文章主要介绍常用激光感知算法学习。 无专精则不能成&#xff0c;无涉猎则不能通。——梁启超 欢迎来到我的博客&#xff0c;一起学习&#xff0c;共同进步。 喜欢的朋友可以关注一下&#xff0c;下…

VR家装提升用户信任度,线上体验家装空间感

近些年&#xff0c;VR家装逐渐被各大装修公司引入&#xff0c;VR全景装修的盛行&#xff0c;大大增加了客户“所见即所得”的沉浸式体验感&#xff0c;不再是传统二维平面的看房模式&#xff0c;而是让客户通过视觉、听觉、交互等功能更加真实的体验家装后的效果。 对于传统家装…

Blazor 简单组件(1):B_Icon开发

文章目录 前言ICON开发使用 前言 Blazor 简单组件(0)&#xff1a;简单介绍 ICON开发 <i class"Type" style"font-size:(Size)px;color:Color;"></i>code {/// <summary>/// icon类型/// </summary>[Parameter]public string Typ…

基于rsesnet网络架构的图像分类模型

数据预处理部分&#xff1a; 数据增强&#xff1a;torchvision中transforms模块自带功能&#xff0c;比较实用数据预处理&#xff1a;torchvision中transforms也帮我们实现好了&#xff0c;直接调用即可DataLoader模块直接读取batch数据 网络模块设置&#xff1a; 加载预训练…

哨兵2号在SNAP中去云处理

1.Fmask软件对1C级产品进行处理&#xff0c;识别像素类别 不知道Fmask是什么可以先去百度一下 软件下载,链接到github地址 我下载的是4.5版本&#xff0c;无脑安装即可。 双击打开软件&#xff08;需要等一会&#xff09;&#xff0c;长这样 路径选择E:\S2\S2A_MSIL1C_20220…

【uniapp】滚动相关

1、滚动到一定区域&#xff0c;顶部内容置换并置顶 功能&#xff1a; 当我向下滚动时&#xff0c;当关注那一行快到顶部的时候&#xff0c;把左侧区域的内容切换成右侧区域的内容&#xff0c;并置顶 原先我使用v-if来显示隐藏&#xff0c;发现会出现闪屏的现象&#xff0c;后来…

丁基胶塞市场报告-行业现状及未来发展趋势

▌产品定义及统计范围 丁基胶塞具有吸湿率低、化学性好、气密性好及无生理毒副作用等显著特点, 广泛应用于抗生素粉针剂、大输液、冻干制剂等药物的密封包装及导出。 ▌丁基胶塞行业目前现状分析 丁基胶塞市场集中度较低&#xff0c;产品高度分化。全球主要厂商集中在欧美中…

【STM32RT-Thread零基础入门】 2. 新建RT-Thread项目

硬件&#xff1a;STM32F103ZET6、ST-LINK、usb转串口工具 文章目录 前言一、新建RT-Thread项目二、项目结构三、构建项目四、下载程序&#xff08;调试器下载&#xff09;五、终端交互总结 前言 RT-Thread的全称是Real Time Thread&#xff0c;顾名思义&#xff0c;它是一个嵌…

深眸科技|发现AI+3D视觉的价值,技术升级加速视觉应用产品国产替代

随着中国工业化进程的不断深入和智能制造浪潮的影响&#xff0c;工业生产对于机器视觉技术的需求不断攀升&#xff0c;其应用范围覆盖了工业领域的众多行业&#xff0c;包括3C电子、汽车、半导体、新能源、物流等。 据GGII发布的最新数据显示&#xff0c;近年来我国机器视觉市…

spring cloud alibaba 应用无法注册到sentinel dashboard

一。技术背景 由于升级jdk17的需要 我们将项目中的 spring cloud spring cloud alibaba 以及springboot进行了升级 各版本如下 spring cloud 2021.0.5 spring cloud alibaba 2021.0.5.0 spring boot 2.6.13 二。问题表现 当启动项目服务后&#xff0c;服务无法注册到 sentin…

Mongodb:业务应用(2)

需求&#xff1a; 1、获取保存到mongodb库中的搜索记录列表 2、实现删除搜索记录接口 保存搜索记录数据参考上篇Mongodb&#xff1a;业务应用&#xff08;1&#xff09;_Success___的博客-CSDN博客 获取记录列表 1、创建controller package com.heima.search.controller.v1;…

工业软件Halcon的常用功能及常用工具展示

工业软件Halcon的常用功能及常用工具展示 1.BLOB特征2.BLOB差分特征3.光度立体4.特征训练5. 测量拟合6. 频域空间域结合法7.深度学习法总结 1.BLOB特征 官方示例子&#xff1a;surface_scratch.hdev 该程序显示了通过局部阈值和形态学后处理提取表面划痕&#xff0c;一共分为三…