动态通讯录(并不难都能拿下)

请添加图片描述

文章目录

  • 🚀前言
  • 🚀通讯录
    • 实现动态通讯录的初期准备
    • 模块化框架搭建
  • 🚀实现接口函数

🚀前言

铁子们好啊!今天咱们来整一个有意思的玩意——通讯录,相信大家对通讯录并不陌生,那接下来就跟着阿辉把它拿捏了😉

🚀通讯录

实现动态通讯录的初期准备

铁子们都知道通讯录是用来存放联系人信息的,首先我们得定义一个结构体来描述联系人的各项特征,比如:姓名、年龄、性别、电话号、地址等。

#define NAME_MAX 20 //姓名
#define SEX_MAX 5 //性别
#define TELE_MAX 12 //电话
#define ADDR_MAX 30 //地址
//联系人信息
typedef struct people
{char name[NAME_MAX];int age;char sex[SEX_MAX];char numb[TELE_MAX];char addr[ADDR_MAX];
}peo;//重定义

对于通讯录这种数据我们可以通过下面这样的结构体来实现:

//通讯录
typedef struct contact
{peo* data;int size;//记录管理联系人个数int capacity;//记录通讯录容量
}contact;

实际上,上述通讯录的本质是一个顺序表,怎么理解呢?给铁子们上图👇
请添加图片描述
有了数组的首元素地址data、数组的元素个数size以及数组空间的大小capacity,我们可以轻易的管理数组中的元素以及数组的大小
对于通讯录我们要实现六大功能的接口函数:增加联系人信息、删除联系人信息、查找联系人信息、修改联系人信息、打印通讯录以及对通讯录信息排序。

不过为了实现用户和计算机的交互我们首先要实现一个菜单来供用户选择:

void menu()
{printf("------------------------------\n");printf("----     1.添加联系人     ----\n");printf("----     2.删除联系人     ----\n");printf("----     3.查找联系人     ----\n");printf("----     4.修改联系人     ----\n");printf("----     5.打印通讯录     ----\n");printf("----     6.排序通讯录     ----\n");printf("----     0.退出通讯录     ----\n");printf("------------------------------\n");
}

模块化框架搭建

有了以上的准备我们可以搭建出通讯录的框架,同样这里我们使用模块化的方式进行设计
通讯录分为test.c、contact.c两个源文件和contact.h一个头文件:

  • test.c:主函数接口引入

  • contact.c:函数功能的实现

  • contact.h:头文件引入、函数声明、结构体声明

contact.h头文件

#include<stdio.h>
#include<string.h>
#include<stdlib.h>#define NAME_MAX 20 //姓名
#define SEX_MAX 5 //性别
#define TELE_MAX 12 //电话
#define ADDR_MAX 30 //地址
//联系人信息
typedef struct people
{char name[NAME_MAX];int age;char sex[SEX_MAX];char numb[TELE_MAX];char addr[ADDR_MAX];
}peo;
//通讯录
typedef struct contact
{peo* data;int size;//管理联系人int capacity;//记录通讯录容量
}contact;//接口函数实现通讯录各项功能
//增加联系人
void AddCon(contact* p);
//删除联系人
void DeteleCon(contact* p);
//查找联系人
void SearchCon(contact* p);
//修改联系人
void ModifyCon(contact* p);
//打印通讯录
void PrintCon(contact* p);
//释放通讯录内存
void DistroyCon(contact* p);
//给联系人排序
void SortCon(contact* p);

test.c源文件

#include"contact.h"
enum Op//使用枚举维护代码的可读性
{Exit,//0Add,//1Delete,//2Search,//3Modify,//4Print,//5sort,//6
};void menu()//打印菜单
{printf("------------------------------\n");printf("----     1.添加联系人     ----\n");printf("----     2.删除联系人     ----\n");printf("----     3.查找联系人     ----\n");printf("----     4.修改联系人     ----\n");printf("----     5.打印通讯录     ----\n");printf("----     6.排序通讯录     ----\n");printf("----     0.退出通讯录     ----\n");printf("------------------------------\n");
}int main()
{//声明通讯录变量con并初始化通讯录contact con = { NULL, 0, 0 };int input = 0;do {menu();printf("请选择要使用的功能:>");scanf("%d", &input);switch (input){case Add:AddCon(&con);break;case Delete:DeteleCon(&con);break;case Search:SearchCon(&con);break;case Modify:ModifyCon(&con);break;case Print:PrintCon(&con);break;case sort:SortCon(&con);break;case Exit:DistroyCon(&con);//退出程序时释放内存break;default:printf("输入错误,请重新输入!\n");}} while (input);return 0;
}

🚀实现接口函数

有了上述的框架,我们只需要在contact.c源文件中实现各项功能的接口函数通讯录就完成了
添加联系人接口:

void AddCon(contact* p)
{if (p == NULL)//先判断传过来的指针是否为空return;//为空直接返回if (p->capacity == p->size)//判断容量与数组元素个数是否相等,相等说明数组该扩容了{//如果进来初始化数组还未分配空间,先让capacity+1if (p->capacity == 0)  p->capacity++;//然后使用realloc开辟空间,后续数组空间不够直接增加一倍原本空间,一举两得peo* pd = (peo*)realloc(p->data, sizeof(peo) * p->capacity);if (pd == NULL)//空间开辟失败直接返回return;p->data = pd;//把开辟空间的首地址赋给datap->capacity *= 2;//开辟完空间capacity倍增}printf("请输入姓名:>");scanf("%s", p->data[p->size].name);printf("请输入年龄:>");scanf("%d", &(p->data[p->size].age));printf("请输入姓别:>");scanf("%s", p->data[p->size].sex);printf("请输入电话:>");scanf("%s", p->data[p->size].numb);printf("请输入地址:>");scanf("%s", p->data[p->size].addr);printf("添加成功!\n");p->size++;//联系人添加成功size自增
}

删除指定联系人接口:
先遍历数组找到要删除的元素,后续我们的查找修改联系人都需要遍历数组进行查找,这里我们封装好一个函数check通过对比名字来实现
查找函数:

//这个函数我们使用static修饰,使其只能在源文件contact.c中使用
static int check(contact* p,char a[])
{int i = 0;for (i = 0; i < p->size; i++){if (strcmp(a, p->data[i].name) == 0)break;//找到后跳出循环}if (i >= p->size)//i如果超出size说明数组中没有改联系人return -1;//返回-1return i;//找到则返回该联系人下标
}

删除指定联系人接口:
如何实现,铁子们看图
请添加图片描述

void DeteleCon(contact* p)
{if (p == NULL)//判断穿入指针是否为空return;if (p->size == 0)//看数组中是否有元素{printf("空的我删个锤子啊!\n");return;}char str[20] = {0};//输入要删除的联系人的姓名printf("请输入要删除联系人的名字:>");scanf("%s", str);int ret = check(p, str);//查找要删除联系人的下标if (ret == -1){printf("查无此人!\n");return;}//上述图片的功能,至删除元素起后一个元素覆盖前一个元素for (int i = ret; i < p->size - 1; i++){p->data[i] = p->data[i + 1];}printf("已成功删除!\n");p->size--;//size自减
}

查找指定联系人接口:
这个很简单

void SearchCon(contact* p)
{if (p == NULL)return;if (p->size == 0){printf("空的我查个锤子!\n");return;}char str[20] = { 0 };printf("请输入要查找的联系人的名字:>");scanf("%s", str);int ret = check(p, str);//查找要找的联系人的下标if (ret == -1){printf("查无此人!\n");return;}//打印要找的联系人的信息printf("%-15s	%-5d	%-8s	%-12s	%-20s\n",p->data[ret].name,p->data[ret].age,p->data[ret].sex,p->data[ret].numb,p->data[ret].addr);
}

修改指定联系人接口:
这个也很简单,找到后修改

void ModifyCon(contact* p)
{if (p == NULL)return;if(p->size == 0){printf("空的我改个锤子!\n");return;}char str[20] = { 0 };printf("请输入要修改的联系人的名字:>");scanf("%s", str);int ret = check(p, str);//查找要找的联系人的下标if (ret == -1){printf("查无此人!\n");return;}//修改联系人内容printf("请输入姓名:>");scanf("%s", p->data[ret].name);printf("请输入年龄:>");scanf("%d", &(p->data[ret].age));printf("请输入姓别:>");scanf("%s", p->data[ret].sex);printf("请输入电话:>");scanf("%s", p->data[ret].numb);printf("请输入地址:>");scanf("%s", p->data[ret].addr);printf("修改成功!\n");
}

打印联系人接口:
打印就更简单了

void PrintCon(contact* p)
{if (p == NULL)return;//下面这一行是为了便于观察printf("%-15s	%-5s	%-8s	%-12s	%-20s\n", "名字", "年龄", "性别", "电话", "地址");for (int i = 0; i < p->size; i++)//遍历数组打印{printf("%-15s	%-5d	%-8s	%-12s	%-20s\n",p->data[i].name,p->data[i].age,p->data[i].sex,p->data[i].numb,p->data[i].addr);}
}

排序联系人接口:

//比较器,利用名字字典序排列
int cmp(const void* p1,const void* p2)
{return strcmp(((peo*)p1)->name, ((peo*)p2)->name);
}
void SortCon(contact* p)
{if (p == NULL)return;if (p->size < 2)//元素小于两个不需要排序return;//利用库函数qsort排序,得自己定义比较器qsort(p->data, p->size, sizeof(p->data[0]), cmp);printf("排序完成!\n");
}

释放通讯录空间接口:

void DistroyCon(contact* p)
{free(p->data);//释放动态内存p->data = NULL;//指针置空//下面变量置0p->size = 0;p->capacity = 0;printf("内存释放!\n");
}

到这里动态通讯录也是实现完成了,并不是很难相信大家都能轻易拿下,希望这篇博客能让大家有所收获, 如果觉得阿辉写得不错的话,记得给个赞呗,你们的支持是我创作的最大动力🌹

请添加图片描述

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

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

相关文章

基于ssm小区疫情防控管理系统论文

摘 要 现代经济快节奏发展以及不断完善升级的信息化技术&#xff0c;让传统数据信息的管理升级为软件存储&#xff0c;归纳&#xff0c;集中处理数据信息的管理方式。本小区疫情防控管理系统就是在这样的大环境下诞生&#xff0c;其可以帮助管理者在短时间内处理完毕庞大的数据…

微信小程序集成腾讯地图

微信小程序集成腾讯地图 微信小程序集成腾讯地图&#xff0c;实现用户附近停车位搜索显示。 腾讯开发者Key申请 官方地址&#xff1a;https://lbs.qq.com/ 下载工具JS 微信小程序JS代码 // pages/check-services.js const app getApp() // 引入SDK核心类 var QQMapWX …

Nginx配合Vue的history模式

加上一行代码就行&#xff1a; try_files $uri $uri/ /index.html;

PyQt6 QTreeWidget树控件

锋哥原创的PyQt6视频教程&#xff1a; 2024版 PyQt6 Python桌面开发 视频教程(无废话版) 玩命更新中~_哔哩哔哩_bilibili2024版 PyQt6 Python桌面开发 视频教程(无废话版) 玩命更新中~共计46条视频&#xff0c;包括&#xff1a;2024版 PyQt6 Python桌面开发 视频教程(无废话版…

Easy Excel生成复杂下Excel模板(下拉框)给用户下载

引言 文件的下载是一个非常常见的功能&#xff0c;也有一些非常好的框架可以使用&#xff0c;这里我们就介绍一种比较常见的场景&#xff0c;下载Excel模版&#xff0c;导入功能通常会配有一个模版下载的功能&#xff0c;根据下载的模版&#xff0c;填充数据然后再上传。 需求…

TrustGeo代码理解(七)preprocess.py

代码链接:https://github.com/ICDM-UESTC/TrustGeo 一、导入各种模块和数据库 # Load data and IP clusteringimport math import random import pandas as pd import numpy as np import argparse from sklearn import preprocessing from lib.utils import MaxMinScaler …

设计模式——外观模式(结构型)

引言 外观模式是一种结构型设计模式&#xff0c; 能为程序库、 框架或其他复杂类提供一个简单的接口。 ​ 问题 假设你必须在代码中使用某个复杂的库或框架中的众多对象。 正常情况下&#xff0c; 你需要负责所有对象的初始化工作、 管理其依赖关系并按正确的顺序执行方法等。…

C#动态生成带参数的小程序二维码

应用场景 在微信小程序管理后台&#xff0c;我们可以生成下载标准的小程序二维码&#xff0c;提供主程序入口功能。在实际应用开发中&#xff0c;小程序二维码是可以携带参数的&#xff0c;可以动态进行生成&#xff0c;如如下场景&#xff1a; 1、不同参数决定的显示界面不同…

MQTT中的保留消息(Retained Message)

一条保留消息是MQTT中保留标志设置为true的一条普通消息。代理&#xff08;broker&#xff09;为对应的主题保留最后的保留消息及对应的QoS。每一个订阅了该主题的客户端在订阅之后会马上收到这个保留消息。代理&#xff08;broker&#xff09;为每个主题只存储一条保留消息。本…

Docker本地镜像发布到阿里云或私有库

本地镜像发布到阿里云流程 &#xff1a; 1.自己生成个要传的镜像 2.将本地镜像推送到阿里云: 阿里云开发者平台:开放云原生应用-云原生&#xff08;Cloud Native&#xff09;-云原生介绍 - 阿里云 2.1.创建仓库镜像&#xff1a; 2.1.1 选择控制台&#xff0c;进入容器镜像服…

MQTT的奇妙之旅:探索RabbitMQ Web MQTT插件的威力【RabbitMQ 十一】

欢迎来到我的博客&#xff0c;代码的世界里&#xff0c;每一行都是一个故事 MQTT的奇妙之旅&#xff1a;探索RabbitMQ Web MQTT插件的威力 前言第一&#xff1a;揭秘RabbitMQ Web MQTT插件背景和目的&#xff1a;MQTT 协议简介&#xff1a;WebSockets 和 MQTT 的融合&#xff1…

谣言检测常用数据集汇总

Pheme-R 获取地址&#xff1a;https://figshare.com/articles/dataset/PHEME_rumour_scheme_dataset_journalism_use_case/2068650 PHEME社交媒体谣言数据集:这些谣言与9条不同的突发新闻有关。它是为分析社交媒体谣言而创建的&#xff0c;并包含由谣言推文发起的推特对话;这些…

竞赛保研 python区块链实现 - proof of work工作量证明共识算法

文章目录 0 前言1 区块链基础1.1 比特币内部结构1.2 实现的区块链数据结构1.3 注意点1.4 区块链的核心-工作量证明算法1.4.1 拜占庭将军问题1.4.2 解决办法1.4.3 代码实现 2 快速实现一个区块链2.1 什么是区块链2.2 一个完整的快包含什么2.3 什么是挖矿2.4 工作量证明算法&…

flink安装

什么是flink flink是一个分布式&#xff0c;高性能&#xff0c;随时可用的以及准确的流处理计算框架&#xff0c; flink可以对无界数据&#xff08;流处理&#xff09;和有界数据&#xff08;批处理&#xff09;进行有状态计算&#xff08;flink天生支持状态计算&#xff09;…

开源 CAD 计算机辅助设计软件,基于 Node.js 开发,使用浏览器进行访问-供大家学习研究参考

下载&#xff1a;开源CAD计算机辅助设计软件&#xff0c;基于Node.js开发&#xff0c;使用浏览器进行访问-供大家学习研究参考资源-CSDN文库 https://download.csdn.net/download/weixin_43097956/88623022

Web开发:ibatis的使用笔记

一、简介 ibatis是一个基于SQL映射支持Java和.NET的持久层框架&#xff1a; 1.如下所示id是对应程序的statement&#xff0c;resultClass需要填写SQL查询到的字段对应的类的命名空间类名&#xff08;DAO.QueryForList<实体类>&#xff09;&#xff0c;以此完成持久层和…

Redis新数据类型-Bitmaps

目录 Bitmaps 简介 命令 1. setbit (1) 格式 (2) 实例 2. getbit (1) 格式 (2) 实例 3. bitcount (1) 格式 (2) 实例 4. bitop (1) 格式 (2) 实例 我的其他博客 Bitmaps 简介 Bitmaps 是 Redis 的一种新数据类型&#xff0c;它是一种用于存储位信息的数据结构&…

【FPGA】Verilog:解码器 | 实现 2-4 解码器

实践内容&#xff1a;解释 2 至 4 解码器的结果和仿真过程 (包括真值表创建和 k 映射、AND 门&#xff09;。 0x00 解码器&#xff08;Decoder&#xff09; 解码器是一种根据输入信号从多个输出 bit 中只选择一个的设备。 例如&#xff0c;如果有一个解码器接收一个 2 位二进…

基于spacy的句法依存、实体识别、分析

文章目录 简介spaCy特性&#xff1a; 系统环境与版本安装应用示例参考文献 简介 spaCy spaCy 是一个 Python 和 CPython 的 NLP 自然语言文本处理库。因此它是一个非常快的库。它建立在最新的研究基础上&#xff0c;从设计的第一天起就被用于实际产品中。 spaCy 自带预训练的…

好用的硬盘分区工具,傲梅分区助手 V10.2

傲梅分区助手软件可以帮助用户在硬盘上创建、调整、合并、删除分区&#xff0c;以及管理磁盘空间等操作。它可以帮助你进行硬盘无损分区操作。 支持系统 目前这款软件支持 Windows 7、Windows 8、Windows 10、Windows 11 等个人系统&#xff0c;还支持 Windows 2012/2016/2019…