超详细C语言实现——通讯录
目录
一、介绍
二、源代码
test.c:
Contact.c:
Contact.h:
代码运行结果:
三、开始实现
1.基本框架:
2.添加联系人:
3.显示联系人信息:
4.删除联系人信息:
5.查看指定联系人信息:
6.修改联系人信息:
总结
一、介绍
通讯录相信大家都不陌生,既然大家已经来参考或学习了,说明大家已经基本掌握了C语言的基础语法和一些基本套路了,后续有不懂或者建议的地方,欢迎大家在评论区讨论。
二、源代码
test.c:
#include "contact.h" //测试通讯录void menu() {printf("**********************************\n");printf("****** 1.add 2.del ******\n");printf("****** 3.search 4.modify ******\n");printf("****** 5.show 0.exit ******\n");printf("**********************************\n");printf("**********************************\n"); }void test() {int input = 0;Contact con;InitContact(&con);//初始化通讯录结构体do{menu();printf("请选择:>");scanf("%d", &input);switch (input){case 1:AddContact(&con);break;case 2:DelContact(&con);break;case 3:SearchContact(&con);break;case 4:ModifyContact(&con);break;case 5:ShowContact(&con);break;case 0:printf("退出成功!\n");break;default:printf("输入无效,请重新选择!\n");break;}} while (input); }int main() {test();return 0; }
Contact.c:
//函数的实现 #include "Contact.h"//初始化通讯录结构体 void InitContact(Contact* p) {memset(p->data, 0, sizeof(p->data));p->sz = 0; }//增加联系人信息 void AddContact(Contact* p) {//判断通讯录是否塞满if (p->sz == Max){printf("通讯录已满,无法添加\n");return;}printf("请输入要添加的联系人的姓名:>");scanf("%s", p->data[p->sz].name);printf("请输入要添加的联系人的性别:>");scanf("%s", p->data[p->sz].sex);printf("请输入要添加的联系人的电话号码:>");scanf("%s", p->data[p->sz].tala);printf("请输入要添加的联系人的地址:>");scanf("%s", p->data[p->sz].addr);p->sz++;printf("添加联系人成功!\n"); }//展示联系人信息 void ShowContact(const Contact* p) {//显示标题printf("%-5s\t%-5s\t%-12s\t%-10s\n", "姓名", "性别", "电话号码", "地址");for (int i = 0; i < p->sz; i++){printf("%-5s\t%-5s\t%-12s\t%-10s\n",p->data[i].name,p->data[i].sex,p->data[i].tala,p->data[i].addr);} }//查找联系人 int Findname(Contact* p, char name1[]) {int i = 0;for (i = 0; i < p->sz; i++){if (strcmp(p->data[i].name, name1) == 0){return i;}}//没找到return -1; }//删除指定联系人信息 void DelContact(Contact* p) {if (p->sz == 0){printf("通讯录为空!\n");return;}char name1[Max_name] = { 0 };printf("请输入你要删除的联系人姓名:>");scanf("%s", name1);int del = Findname(p, name1);if (del == -1){printf("该通讯录不存在这个人!\n");return;}int i = 0;for (i = del; i < p->sz - 1; i++){p->data[i] = p->data[i + 1];}p->sz--;printf("删除联系人成功!\n"); }//查找指定联系人 void SearchContact(const Contact* p) {char name[Max_name] = { 0 };printf("请输入你要查看的联系人的姓名:>");while (getchar()!= '\n');scanf("%s", name);int i = Findname(p, name);if (i == -1){printf("该通讯录不存在该联系人\n");}else{//显示标题printf("%-5s\t%-5s\t%-12s\t%-10s\n", "姓名", "性别", "电话号码", "地址");printf("%-5s\t%-5s\t%-12s\t%-10s\n",p->data[i].name,p->data[i].sex,p->data[i].tala,p->data[i].addr);} }//修改联系人信息 void ModifyContact(Contact* p) {char name[Max_name] = { 0 };printf("请输入你要修改的联系人的姓名:>");while (getchar() != '\n');scanf("%s", name);int i = Findname(p, name);if (i == -1){printf("该通讯录不存在该联系人\n");}else{printf("请重新输入该联系人的姓名:>");scanf("%s", p->data[i].name);printf("请重新输入该联系人的性别:>");scanf("%s", p->data[i].sex);printf("请重新输入该联系人的电话号码:>");scanf("%s", p->data[i].tala);printf("请重新输入该联系人的地址:>");scanf("%s", p->data[i].addr);}printf("修改成功!\n"); }
Contact.h:
#define _CRT_SECURE_NO_WARNINGS 1 #pragma once #define Max 100 #define Max_name 20 #define Max_sex 5 #define Max_tele 12 #define Max_addr 30//存放函数的类型和声明 #include<string.h> #include<stdio.h>typedef struct PeoInfo {char name[Max_name];char sex[Max_sex];char tala[Max_tele];char addr[Max_addr];}PeoInfo;//通讯录结构体 typedef struct Contact {PeoInfo data[Max];int sz; }Contact;//函数声明//初始化通讯录结构体 void InitContact(Contact* p);//增加联系人信息 void AddContact(Contact* p);//展示联系人信息 void ShowContact(Contact* p);//删除联系人信息 void DelContact(Contact* p);//查找指定联系人信息 void SearchContact(const Contact* p);//修改联系人信息 void ModifyContact(Contact* p);
代码运行结果:
三、开始实现
1.基本框架:
本次实现通讯录,采用多文件的方法进行实现,既然大家学到了通讯录,应该几乎都接触过多文件操作,所谓多文件操作即:
①:函数的声明、define的宏定义、以及结构体的声明等等放在.h文件。(contact.h)
②:函数的定义放在.c文件。(contact.c)
③:main函数和一些基本框架可以单独放在另一个.c文件。(test.c)。
既然是通讯录,我们就需要一个保存通讯录人员的结构体以及保存人员信息的结构体,声明放在contact.h文件中:
①:本次人员信息我们放在结构体PerInfo中,其中给了姓名、性别、电话、地址,大家可以根据自身想法,添加其他信息。
②:然后第二个结构体Contact用于保存联系人,这里以上限为100个联系人为例,所以成员有一个PerInfo结构体数组,然后还有一个整型变量sz用于记录现有人数,增加一个人,sz+1;删除一个人,sz-1。
代码如下:
#pragma once #define Max 100 #define Max_name 20 #define Max_sex 5 #define Max_tele 12 #define Max_addr 30typedef struct PeoInfo {char name[Max_name];char sex[Max_sex];char tala[Max_tele];char addr[Max_addr];}PeoInfo;//通讯录结构体 typedef struct Contact {PeoInfo data[Max];int sz; }Contact;
然后本次框架依然用do while循环套switch case语句,以便于选择不同的功能,这里我们放在test.c文件中:
#include "contact.h" //测试通讯录void menu() {printf("**********************************\n");printf("****** 1.add 2.del ******\n");printf("****** 3.search 4.modify ******\n");printf("****** 5.show 0.exit ******\n");printf("**********************************\n");printf("**********************************\n"); }void test() {int input = 0;Contact con;InitContact(&con);//初始化通讯录结构体do{menu();printf("请选择:>");scanf("%d", &input);switch (input){case 1:break;case 2:break;case 3:break;case 4:break;case 5:break;case 0:break;default:break;}} while (input); }int main() {test();return 0; }
①:因为相关头文件在contact.h文件中,所以不论是在contact.c文件还是在test。c文件中,我们都需要包含一下自己的头文件contact.h。
②:然后为了美观,写一个菜单函数menu,大家可自行设置。
③:首先我们必须要有一个Contact的结构体变量con,然后创建InitContact函数对其成员简单的初始化:
这里数组有100个空间,用循环初始化太麻烦,所以我们用到一个库函数memset,具体介绍可以参考http://t.csdn.cn/wu8iX
④:应该大部分人都使用过do while套switch case,因为这样我们可以根据菜单函数来进行选择,输入不同数字进入不同功能函数,函数结束后又可以循环输入,当输入0时,do while结束,即整个系统结束。
2.添加联系人:
基本框架搭完,我们就可以实现相关函数了,这里小编建议在写这种类似的程序时,最好一个函数一个函数的实现,这样方便调试和改正。
首先实现添加操作,我们创建AddContact函数来实现添加操作,函数源代码如下:
//增加联系人信息 void AddContact(Contact* p) {//判断通讯录是否塞满if (p->sz == Max){printf("通讯录已满,无法添加\n");return;}printf("请输入要添加的联系人的姓名:>");scanf("%s", p->data[p->sz].name);printf("请输入要添加的联系人的性别:>");scanf("%s", p->data[p->sz].sex);printf("请输入要添加的联系人的电话号码:>");scanf("%s", p->data[p->sz].tala);printf("请输入要添加的联系人的地址:>");scanf("%s", p->data[p->sz].addr);p->sz++;printf("添加联系人成功!\n"); }
①:既然是添加,我们最开始就需要判断通讯录是否填满,若没有填满才继续添加,所以开始用一个if语句,当sz==Max时,即为满。
②:接着只需要依次向对应位置输入数据即可,因为sz表示通讯录现有人数,刚开始为0,而数组的下标也是从0开始,所以直接用sz作为数组下标进行输入数据即可,添加成功后,sz自增1,即表示人数+1,又可用来作为第二次添加时作为数组下标。
③:这里需要注意和理解清楚每个结构体变量和成员以及‘.’操作符和'->'操作符的对应关系。
3.显示联系人信息:
为了方便测试代码是否有误,我们在实现添加操作后就可以先实现展示操作,这样可以检查添加操作是否有误以及后续每完成一个功能,就可以用展示功能来检查。
我们创建函数ShowContact函数来实现展示功能,源代码如下:
//展示联系人信息 void ShowContact(Contact* p) {//显示标题printf("%-5s\t%-5s\t%-12s\t%-10s\n", "姓名", "性别", "电话号码", "地址");//显示信息for (int i = 0; i < p->sz; i++){printf("%-5s\t%-5s\t%-12s\t%-10s\n",p->data[i].name,p->data[i].sex,p->data[i].tala,p->data[i].addr);} }
①:我们首先先打印标题,方便查看。
②:我们只需用一个for循环,在用和结构体找到对应的值打印出来即可。
③:这里值得注意的是排版问题,一些缩进和排版是影响美观的,大家可自行设置,也可参考上诉源代码。
4.删除联系人信息:
我们创建DelContact函数来实现删除操作,源代码如下:
//删除指定联系人信息 void DelContact(Contact* p) {if (p->sz == 0){printf("通讯录为空!\n");return;}char name1[Max_name] = { 0 };printf("请输入你要删除的联系人姓名:>");scanf("%s", name1);int del = Findname(p, name1);if (del == -1){printf("该通讯录不存在这个人!\n");return;}int i = 0;for (i = del; i < p->sz - 1; i++){p->data[i] = p->data[i + 1];}p->sz--;printf("删除联系人成功!\n"); }
①:既然是删除,所以我们最开始应该判断一下通讯录是否为空;
②:然后创建一个临时数组char name1[],用于用户输入要删除的联系人的姓名;
③:接着我们需要判断通讯录是否存在这个人,所以这里又创建Findname函数,用于查找指定联系人,源代码如下:
//查找联系人 int Findname(Contact* p, char name1[]) {int i = 0;for (i = 0; i < p->sz; i++){if (strcmp(p->data[i].name, name1)){return i;}}//没找到return -1; }
这里值得注意的是循环里面的if语句,很多人在判断条件里面喜欢用“==”,但我们要注意,姓名是字符串,这里是两个字符串相比较,所以不能直接用“==”,所以这里用到字符串函数strcmp,具体用法参考:http://t.csdn.cn/qD0LQ
④:当没找到时,提示后直接返回;若找到了,就进行删除操作;
因为我们使用的是数组,所以删除操作简单,只需要先找到该联系人的位置del,然后将该位置后面的内容依次向前进行覆盖,最后现有人数sz自减一即可,所以这里用到一个for循环。
5.查看指定联系人信息:
我们创建SearchContact函数实现此操作,源代码如下:
//查找指定联系人 void SearchContact(const Contact* p) {char name[Max_name] = { 0 };printf("请输入你要查看的联系人的姓名:>");while (getchar()!= '\n');scanf("%s", name);int i = Findname(p, name);if (i == -1){printf("该通讯录不存在该联系人\n");}else{//显示标题printf("%-5s\t%-5s\t%-12s\t%-10s\n", "姓名", "性别", "电话号码", "地址");printf("%-5s\t%-5s\t%-12s\t%-10s\n",p->data[i].name,p->data[i].sex,p->data[i].tala,p->data[i].addr);} }
①:首先创建一个临时数组便于用户输入指定联系人姓名,然后用一个while循环去掉缓冲区多余内容,以便scanf正常读入;
②:接着调用Findname函数,根据返回值进行操作
若返回-1,则该联系人不存在,直接返回;
若不是-1,说明找到了,然后我们打印出该联系人各个信息即可。
6.修改联系人信息:
我们创建ModifyContact函数来实现该操作,源代码如下:
//修改联系人信息 void ModifyContact(Contact* p) {char name[Max_name] = { 0 };printf("请输入你要修改的联系人的姓名:>");while (getchar() != '\n');scanf("%s", name);int i = Findname(p, name);if (i == -1){printf("该通讯录不存在该联系人\n");}else{printf("请重新输入该联系人的姓名:>");scanf("%s", p->data[i].name);printf("请重新输入该联系人的性别:>");scanf("%s", p->data[i].sex);printf("请重新输入该联系人的电话号码:>");scanf("%s", p->data[i].tala);printf("请重新输入该联系人的地址:>");scanf("%s", p->data[i].addr);}printf("修改成功!\n"); }
①:前面和查找联系人相同,需要用户先输入要修改的联系人的姓名,然后判断是否存在;
②:若存在的话只需返回该下标,然后对该下标的信息重新输入数据即可,比较简单。
总结
本次小编只是简单实现一个通讯录,方便大家寻找思路和入手方法,有很多漏洞以及改进大家可以自行实现,本次知识到此为止,希望对大家有所帮助!
相关文章:

超详细C语言实现——通讯录
目录 一、介绍 二、源代码 test.c: Contact.c: Contact.h: 代码运行结果: 三、开始实现 1.基本框架: 2.添加联系人: 3.显示联系人信息: 4.删除联系人信息: 5.查看指定联系人信息: 6.修改联系人…...

zabbix监控添加监控项及其监控Mysql、nginx
本届主要介绍添加监控项和修改中文乱码,监控mysql,nginx服务 一、zabbix监控添加监控项 1、配置agent服务器 在配置文件中添加: UserParameterlsq_userd,free -m | grep Mem | awk { print $3 } 服务器内存使用量 UserParameterdu,…...
Docker 部署 MongoDB 服务
拉取最新版本的 MongoDB 镜像: $ sudo docker pull mongo:latest在本地预先创建好 db 和 configdb 目录, 用于映射 MongoDB 容器内的 /data/db 和 /data/configdb 目录。 使用以下命令来运行 MongoDB 容器: $ sudo docker run -itd --name mongo --privilegedtru…...

QUIC协议报文解析(三)
在前面的两篇文字里我们简单介绍了QUIC的发展历史,优点以及QUIC协议的连接原理。本篇文章将会以具体的QUIC报文为例,详细介绍QUIC报文的结构以及各个字段的含义。 早期QUIC版本众多,主要有谷歌家的gQUIC,以及IETF致力于将QUIC标准…...

pytorch迁移学习训练图像分类
pytorch迁移学习训练图像分类 一、环境配置二、迁移学习关键代码三、完整代码四、结果对比 代码和图片等资源均来源于哔哩哔哩up主:同济子豪兄 讲解视频:Pytorch迁移学习训练自己的图像分类模型 一、环境配置 1,安装所需的包 pip install …...

SQL 如何提取多级分类目录
前言 POI数据处理,原始数据为csv格式,整理入库至PostGreSQL,本例使用PostGreSQL13版本。 一、POI POI(一般作为Point of Interest的缩写,也有Point of Information的说法),通常称作兴趣点&am…...

从中序遍历和后序遍历构建二叉树
题目描述 106. 从中序与后序遍历序列构造二叉树 中等 1.1K 相关企业 给定两个整数数组 inorder 和 postorder ,其中 inorder 是二叉树的中序遍历, postorder 是同一棵树的后序遍历,请你构造并返回这颗 二叉树 。 示例 1: 输入࿱…...

《计算机视觉中的多视图几何》笔记(11)
11 Computation of the Fundamental Matrix F F F 本章讲述如何用数值方法在已知若干对应点的情况下求解基本矩阵 F F F。 文章目录 11 Computation of the Fundamental Matrix F F F11.1 Basic equations11.1.1 The singularity constraint11.1.2 The minimum case – sev…...

UE5 ChaosVehicles载具研究
一、基本组成 载具Actor类名称:WheeledVehiclePawn Actor最原始的结构 官方增加了两个摇臂相机,可以像驾驶游戏那样切换多机位、旋转观察 选择骨骼网格体、动画蓝图类、开启物理模拟 二、SportsCar_Pawn 角阻尼:物体旋转的阻力。数值越大…...

数据通信——应用层(域名系统)
引言 TCP到此就告一段落,这也意味着传输层结束了,紧随其后的就是TCP/IP五层架构的应用层。操作系统、编程语言、用户的可视化界面等等都要通过应用层来体现。应用层和我们息息相关,我们使用电子设备娱乐或办公时,接触到的就是应用…...

Visual Studio 更新:远程文件管理器
Visual Studio 中的远程文件管理器可以用来访问远程机器上的文件和文件夹,通过 Visual Studio 自带的连接管理器,可以实现不离开开发环境直接访问远程系统,这确实十分方便。 自从此功能发布以来,VS 开发团队努力工作,…...
ChatGPT追祖寻宗:GPT-3技术报告要点解读
论文地址:Language Models are Few-Shot Learners 往期相关文章: ChatGPT追祖寻宗:GPT-1论文要点解读_五点钟科技的博客-CSDN博客ChatGPT追祖寻宗:GPT-2论文要点解读_五点钟科技的博客-CSDN博客 本文的标题之所以取名技术报告而不…...
java easyexcel 导出多级表头
maven <dependency><groupId>com.alibaba</groupId><artifactId>easyexcel</artifactId><version>${easyexcel.version}</version> </dependency> 导出行的对象 import com.alibaba.excel.annotation.ExcelIgnore; import …...

rar格式转换zip格式,如何做?
平时大家压缩文件时对压缩包格式可能没有什么要求,但是,可能因为工作需要,我们要将压缩包格式进行转换,那么我们如何将rar格式转换为其他格式呢?方法如下: 工具:WinRAR 打开WinRAR,…...
Java中的构造方法
在Java中,构造方法是类的特殊方法,用于初始化对象的实例变量和执行其他必要的操作,以便使对象能够正确地工作。构造方法与类同名,没有返回类型,并且在创建对象时自动调用。 以下是构造方法的一些基本特性:…...
【Java】fastjson
Fastjson简介 Fastjson是阿里巴巴的团队开发的一款Java语言实现的JSON解析器和生成器,它具有简单易用、高性能、高可用性等优点,适用于Java开发中的数据解析和生成。Fastjson的主要特点包括: 简单易用:Fastjson提供了简单易用的…...

JMeter之脚本录制
【软件测试面试突击班】如何逼自己一周刷完软件测试八股文教程,刷完面试就稳了,你也可以当高薪软件测试工程师(自动化测试) 前言: 对于一些JMeter初学者来说,录制脚本可能是最容易掌握的技能之一。…...
计算机网络的相关知识点总结
1.谈一谈对OSI七层模型和TCP/IP四层模型的理解? 不管是OSI七层模型亦或是TCP/IP四层模型,它们的提出都有一个共同的目的:通过分层来将复杂问题细化,通过各个层级之间的相互配合来更好的解决计算机中出现的问题。 说到分层…...

WPF实现轮播图(图片、视屏)
✅作者简介:2022年博客新星 第八。热爱国学的Java后端开发者,修心和技术同步精进。 🍎个人主页:Java Fans的博客 🍊个人信条:不迁怒,不贰过。小知识,大智慧。 💞当前专栏…...

【Vue.js】使用Element搭建首页导航左侧菜单
目录 Mock.js 是什么 有什么好处 安装mockjs 编辑 引入mockjs mockjs使用 login-mock Bus事物总线 首页导航栏与左侧菜单搭建 结合总线完成组件通讯 Mock.js 是什么 Mock.js是一个用于生成随机数据的模拟数据生成器。它可以帮助开发人员模拟接口请求,生…...

【网络安全产品大调研系列】2. 体验漏洞扫描
前言 2023 年漏洞扫描服务市场规模预计为 3.06(十亿美元)。漏洞扫描服务市场行业预计将从 2024 年的 3.48(十亿美元)增长到 2032 年的 9.54(十亿美元)。预测期内漏洞扫描服务市场 CAGR(增长率&…...

基于当前项目通过npm包形式暴露公共组件
1.package.sjon文件配置 其中xh-flowable就是暴露出去的npm包名 2.创建tpyes文件夹,并新增内容 3.创建package文件夹...

现代密码学 | 椭圆曲线密码学—附py代码
Elliptic Curve Cryptography 椭圆曲线密码学(ECC)是一种基于有限域上椭圆曲线数学特性的公钥加密技术。其核心原理涉及椭圆曲线的代数性质、离散对数问题以及有限域上的运算。 椭圆曲线密码学是多种数字签名算法的基础,例如椭圆曲线数字签…...

ElasticSearch搜索引擎之倒排索引及其底层算法
文章目录 一、搜索引擎1、什么是搜索引擎?2、搜索引擎的分类3、常用的搜索引擎4、搜索引擎的特点二、倒排索引1、简介2、为什么倒排索引不用B+树1.创建时间长,文件大。2.其次,树深,IO次数可怕。3.索引可能会失效。4.精准度差。三. 倒排索引四、算法1、Term Index的算法2、 …...

NLP学习路线图(二十三):长短期记忆网络(LSTM)
在自然语言处理(NLP)领域,我们时刻面临着处理序列数据的核心挑战。无论是理解句子的结构、分析文本的情感,还是实现语言的翻译,都需要模型能够捕捉词语之间依时序产生的复杂依赖关系。传统的神经网络结构在处理这种序列依赖时显得力不从心,而循环神经网络(RNN) 曾被视为…...

JUC笔记(上)-复习 涉及死锁 volatile synchronized CAS 原子操作
一、上下文切换 即使单核CPU也可以进行多线程执行代码,CPU会给每个线程分配CPU时间片来实现这个机制。时间片非常短,所以CPU会不断地切换线程执行,从而让我们感觉多个线程是同时执行的。时间片一般是十几毫秒(ms)。通过时间片分配算法执行。…...

优选算法第十二讲:队列 + 宽搜 优先级队列
优选算法第十二讲:队列 宽搜 && 优先级队列 1.N叉树的层序遍历2.二叉树的锯齿型层序遍历3.二叉树最大宽度4.在每个树行中找最大值5.优先级队列 -- 最后一块石头的重量6.数据流中的第K大元素7.前K个高频单词8.数据流的中位数 1.N叉树的层序遍历 2.二叉树的锯…...
go 里面的指针
指针 在 Go 中,指针(pointer)是一个变量的内存地址,就像 C 语言那样: a : 10 p : &a // p 是一个指向 a 的指针 fmt.Println(*p) // 输出 10,通过指针解引用• &a 表示获取变量 a 的地址 p 表示…...
HybridVLA——让单一LLM同时具备扩散和自回归动作预测能力:训练时既扩散也回归,但推理时则扩散
前言 如上一篇文章《dexcap升级版之DexWild》中的前言部分所说,在叠衣服的过程中,我会带着团队对比各种模型、方法、策略,毕竟针对各个场景始终寻找更优的解决方案,是我个人和我司「七月在线」的职责之一 且个人认为,…...

在Zenodo下载文件 用到googlecolab googledrive
方法:Figshare/Zenodo上的数据/文件下载不下来?尝试利用Google Colab :https://zhuanlan.zhihu.com/p/1898503078782674027 参考: 通过Colab&谷歌云下载Figshare数据,超级实用!!࿰…...