当前位置: 首页 > news >正文

【C语言】通讯录(静态版本+动态版本)思路解析+完整源代码

通讯录

由于代码比较长,为了增加可读性,分成了contact.h,contact.c,test.c,分别用来声明函数或者类型,实现函数功能,测试代码

contact.h

我们希望通讯录具有增加联系人,删除联系人,显示联系人,找查联系人,修改联系人,排序的功能,联系人的信息具有名字,年龄,性别,电话,地址的信息

由于每次对通讯录进行操作都要把data数组和存的联系人的个数sz传过去,那干脆把他们两个打包到一个结构体类型struct contact里面

枚举类型是为了增加test.c里面switch语句选项的可读性,默认第一个成员也就是EXIT就是0,那么我们就可以把switch语句里面的0换成EXIT了。

test.c

contact.c

首先把所有data数组的所有内容以及p->sz初始化成0

增加联系人的函数

一次性增加一个联系人的信息

数字表示打印多少位,负号表示左对齐,\t表示插入一个制表符,能够让每一行对齐

在查找联系人,删除联系人,修改联系人信息的函数中,我们都需要先找到某个联系人,为了避免写三份类似的代码,我们这里使用了一个函数。

查找联系人的函数

修改信息的函数

排序的函数

像这样静态版本的通讯录问题还是比较大的,首先就是我们不管存多少个联系人的信息,上来都创建了一个100个元素的数组,这样对内存的开销就比较大,如果我们存的信息少,就浪费了内存,如果存的太多,又要去修改最大容量,在我们学习了动态内存开辟之后,我们可以对通讯录进行如下修改:通讯录刚上来可以存放三个联系人的信息,当通讯录满了之后,自动扩充两个人的名额。于是我们就可以把data数组改成一个指针,为了尽可能少的改动原来的代码,我们把这个指针的名字也叫做data。这与原来数组名的含义都是地址,现在data是一个people*类型的指针,我们可以把使用malloc,realloc函数开辟的内存首地址存到里面去。

那么我们先对以前的contact类型进行以下修改

实际上需要修改的函数只有初始化通讯录的函数和增加联系人的函数。

首先使用malloc开辟一块能存放三个people类型变量的空间,并返回首地址存到data里面去。这里申请了空间由于后面要用,所以并没有及时释放掉,最后关闭通讯录的时候再释放即可。

然后是增加联系人的函数,在增加之前我们先要判断一下通讯录是不是已经满了,我们使用下面的函数来实现这个功能

由于realloc增容可能会失败,因此必须检查,在增容完毕之后要应该更改掉当前的最大容量capacity。

然后在添加联系人的函数中调用这个检查容量的函数

由于以上所有动态内存开辟的空间都没有被释放掉,因此我们在推出这个通讯录的时候应该及时释放掉,在test函数这里调用一个用来释放内存的函数

这个函数也是需要我们自己编写的

这样我们的通讯录就是动态版本的了。

源代码

test.c

#define _CRT_SECURE_NO_WARNINGS
#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 = {0};do {menu();printf("请选择功能\n");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 EXIT:release(&con);printf("退出通讯录\n");break;default:printf("输入错误,请重新选择\n");}} while (input);
}
int main() {test();return 0;
}

contact.c

#define _CRT_SECURE_NO_WARNINGS
#include"contact.h"
//初始化通讯录的函数
void initcontact(contact* p) {p->data = (people*)malloc(DEFAULT_NUM *sizeof(people));//刚上来容量是3if (p->data == NULL) {perror("initcontact");return;}p->sz = 0;p->capacity = DEFAULT_NUM;
}
int check_capacity(contact*p) {if (p->capacity == DEFAULT_NUM) {//扩大容量people* ptr=(people*)realloc(p->data, (DEFAULT_NUM + INC) * sizeof(people));//一个变量名为ptr的people*类型指针,用来接收调整之后的空间首地址if (ptr == NULL) {perror(check_capacity);return 0;}else {p->data = ptr;//这个ptr可能是原来的data,也可能不是,增容成功之后赋给datap->capacity += INC;return 1;}}return 1;//压根不需要增容,也返回1
}
//添加联系人的函数,动态版本
void addcontact(contact* p) {int ret = check_capacity(p);if (0 == ret) {return;}printf("请输入名字\n");scanf("%s", p->data[p->sz].name);printf("请输入年龄\n");scanf("%d", &(p->data[p->sz].age));printf("请输入性别\n");scanf("%s", p->data[p->sz].sex);printf("请输入电话号码\n");scanf("%s", p->data[p->sz].tele);printf("请输入地址\n");scanf("%s", p->data[p->sz].address);p->sz++;printf("增加联系人成功\n");
}
//显示联系人的函数
void showcontact(const contact* p) {int i = 0;for (i = 0; i < p->sz; i++) {//打印标题printf("%-10s\t,%-4s\t,%-5s\t,%-12s\t,%-30s\n", "名字", "年龄", "性别", "电话", "地址");printf("%-10s\t,%-4d\t,%-5s\t,%-12s\t,%-30s\n",p->data[i].name,p->data[i].age,p->data[i].sex,p->data[i].tele,p->data[i].address);}
}
//通过名字找查联系人的函数
// 由于在delcontact,searchcontact,modifycontact函数中都需要找查
// 为了避免写三份类似的代码,我们使用函数来实现找查联系人的功能
int find_by_name(contact* p, char name[]) {//找查联系人int i = 0;for (i = 0; i < p->sz; i++) {if (strcmp(p->data[i].name, name) == 0) {return i;//找到了,返回下标}}return -1;//没有找到,返回-1
}
//删除联系人的函数(暂时不考虑两个人的名字相同的情况)
void delcontact(contact* p) {char name[20] = { 0 };printf("请输入要删除的人名字\n");scanf("%s", name);int i = 0;int del = 0;//记录要删除的人信息在data数组中的下标int flag = 0;if (p->sz == 0) {printf("通讯录为空,无法删除\n");}//找查联系人del = find_by_name(p, name);//删除联系人if (del == -1) {printf("要删除的人不存在\n");return;}for (i = del; i < p->sz - 1; i++) {p->data[i] = p->data[i + 1];//循环用后面的元素覆盖前面的元素}p->sz--;//如果要删除最后一个联系人,也就是下标为sz-1的那个人的信息//由于刚上来del就是sz-1,不会进入循环,也就不会覆盖掉最后一个元素//但是sz--了,就访问不到最后一个元素了,效果上就好像删除了最后一个联系人printf("删除成功\n");
}
//查找某个联系人的函数
void searchcontact(contact* p) {char name[20] = { 0 };printf("请输入要查找的人的名字\n");scanf("%s", name);int pos = find_by_name(p, name);//返回的就是要找的这个人的信息在data数组中的下标 if (pos == -1) {printf("查无此人\n");return;}else {//打印这一个人的信息printf("%-10s\t,%-4s\t,%-5s\t,%-12s\t,%-30s\n", "名字", "年龄", "性别", "电话", "地址");printf("%-10s\t,%-4d\t,%-5s\t,%-12s\t,%-30s\n",p->data[pos].name,p->data[pos].age,p->data[pos].sex,p->data[pos].tele,p->data[pos].address);}
}
//修改信息的函数
void modifycontact(contact* p) {char name[20] = { 0 };printf("请输入要修改信息的人的名字\n");scanf("%s", name);int pos = find_by_name(p, name);if (pos == -1) {printf("查无此人\n");}else {printf("请输入名字\n");scanf("%s", p->data[pos].name);printf("请输入年龄\n");scanf("%d", &(p->data[pos].age));printf("请输入性别\n");scanf("%s", p->data[pos].sex);printf("请输入电话号码\n");scanf("%s", p->data[pos].tele);printf("请输入地址\n");scanf("%s", p->data[pos].address);printf("修改联系人信息成功\n");}
}
//qsort需要的比较大小的函数
int cmp_by_name(void* str1,void* str2) {return strcmp(((people*)str1)->name, ((people*)str2)->name);
}
//根据名字对信息排序的函数
void sortcontact(contact* p) {qsort(p->data, p->sz, sizeof(p->data[0]), cmp_by_name);printf("排序成功\n");
}
void release(contact* p) {free(p->data);p->data = NULL;//注意是data指向的空间被释放掉,不是p指向的空间被释放掉p->capacity = 0;p->sz = 0;
}

contact.h

#pragma once
//用于各种函数或者类型的声明
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define MAX 100 //通讯录能添加的最大人数
#define DEFAULT_NUM 3//刚上来的默认容量是3
#define INC 2//到达最大容量的时候一次性扩充的个数
typedef struct people {char name[20];int age;char sex[5];char tele[12];char address[30];
}people;//创建结构体类型并重命名为people
typedef struct contact {people* data;//一个名为data的指针变量int sz;//用来记录通讯录里面存了几个人的信息了int capacity;//记录当前最大容量
}contact;
//枚举类型,增加可读性,默认EXIT就是0
enum OPTION {EXIT,ADD,DEL,SEARCH,MODIFY,SHOW,SORT,
};
void initcontact(contact* p);//初始化通讯录的函数,把通讯录中内容初始化为0
void addcontact(contact* p);//增加联系人的函数
void showcontact(const contact* p);//显示所有联系人的函数,显示并不会修改p指向的内容,因此加了const
void delcontact(contact* p);//删除联系人的函数
void searchcontact(contact* p);//找查某个联系人的函数
void modifycontact(contact* p);//修改信息的函数
void sortcontact(contact* p);//根据名字对信息排序的函数
void release(contact* p);//使用完成之后释放动态申请的那些空间的函数

相关文章:

【C语言】通讯录(静态版本+动态版本)思路解析+完整源代码

通讯录 由于代码比较长&#xff0c;为了增加可读性&#xff0c;分成了contact.h&#xff0c;contact.c&#xff0c;test.c&#xff0c;分别用来声明函数或者类型&#xff0c;实现函数功能&#xff0c;测试代码 contact.h 我们希望通讯录具有增加联系人&#xff0c;删除联系人…...

spring boot自动装配及自动装配条件判断

第一步需要在pom.xml文件指定需要导入的坐标 要是没有自动提示需要检查maven有没有 实现代码 /*springboot第三方自动配置实现方法 * 什么是自动配置 自动配置就是springboot启动自动加载的类不需要在手动的控制反转自动的加入bean中 * * *//*第一种方案包扫描 不推荐因为繁琐…...

LeetCode--2298. 周末任务计数

文章目录 1 题目描述2 测试用例3 解题思路 1 题目描述 表: Tasks ------------------- | Column Name | Type | ------------------- | task_id | int | | assignee_id | int | | submit_date | date | -------------------task_id 是该表的主键&#xff08;具有唯一值…...

从零开始学习Netty - 学习笔记 - NIO基础 - ByteBuffer: 简介和基本操作

NIO基础 1.三大组件 1.1. Channel & Buffer Channel 在Java NIO&#xff08;New I/O&#xff09;中&#xff0c;“Channel”&#xff08;通道&#xff09;是一个重要的概念&#xff0c;用于在非阻塞I/O操作中进行数据的传输。Java NIO提供了一种更为灵活和高效的I/O处理方…...

Chatgpt润色文章“咒语”

文章目录 前言一、汉译英二、语法校正三、润色英文段落结构和句子逻辑 前言 一些Chatgpt润色文章常用的命令。 一、汉译英 I am a researcher studying Aerospace Manufacturing and now trying to revise my manuscript which will be submitted to the journal of Nature.I…...

【OpenGL教程2】 简单案例介绍Python 中的 OpenGL

目录 一、介绍二、安装三、编码练习四、结论 一、介绍 在本教程中&#xff0c;我们将学习如何在 Python 中使用PyOpenGL库。OpenGL是一个图形库&#xff0c;受Windows、Linux和MacOS等多个平台支持&#xff0c;也可用于多种其他语言&#xff1b;然而&#xff0c;这篇文章的范围…...

评估方法:CMMI/能力成熟度模型集成

一、什么是CMMI CMMI&#xff0c;全称为Capability Maturity Model Integration&#xff0c;即能力成熟度模型集成。它是由美国卡内基梅隆大学软件工程研究所研发的过程改进模型&#xff0c;也是国际上用于评价软件企业能力成熟度的一项重要标准。 CMMI的目的是帮助软件企业对…...

Gin框架: HTML模板渲染之配置与语法详解

Gin的HTML模板配置 1 &#xff09;单一目录的配置 配置模板目录&#xff0c;在与main.go同级下, 新建目录&#xff0c;下面二选一&#xff0c;仅作举例, 这里选择 tpls templatestpls 在 tpls 目录下新建 news.html <!-- 最简单的 --> <h1>News Page</h1>&l…...

.NET Core WebAPI中使用Log4net 日志级别分类并记录到数据库

一、效果 记录日志为文档 记录日志到数据库 二、添加NuGet包 三、log4net.config代码配置 <?xml version"1.0" encoding"utf-8" ?> <log4net><!-- Debug日志 --><appender name"RollingFileDebug" type"log4net…...

Day36 贪心算法 part05

划分字母区间 一个字母区间仅有几个字母前一个字母区间有的字母后面都没有 合并区间 天才举一反三写出来了...

C#计算矩形面积:通过定义结构 vs 通过继承类

目录 一、涉及到的知识点 1.结构 2.结构和类的区别 3.继承 4.使用类继承提高程序的开发效率 5.属性 &#xff08;1&#xff09;属性定义 &#xff08;2&#xff09;get访问器 &#xff08;3&#xff09;set访问器 6. 属性和字段的区别 二、实例&#xff1a;通过定义…...

【复现】Panalog大数据日志审计系统 RCE漏洞_51

目录 一.概述 二 .漏洞影响 三.漏洞复现 1. 漏洞一&#xff1a; 四.修复建议&#xff1a; 五. 搜索语法&#xff1a; 六.免责声明 一.概述 Panalog大数据日志审计系统定位于将大数据产品应用于高校、 公安、 政企、 医疗、 金融、 能源等行业之中&#xff0c;针对网络流…...

react【五】redux/reduxToolkit/手写connext

文章目录 1、回顾纯函数2、redux2.1 redux的基本使用2.2 通过action修改store的数值2.3 订阅state的变化2.4 目录结构2.5 Redux的使用过程2.6 redux的三大原则2.7 Redux官方图 3、redux在React中的使用4、react-redux使用4.1 react-redux的基本使用4.2 异步请求 redux-thunk4.3…...

.NET开源的一个小而快并且功能强大的 Windows 动态桌面软件 - DreamScene2

前言 很多同学都不愿给电脑设动态壁纸&#xff0c;其中有个重要原因就是嫌它占资源过多。今天大姚分享一个.NET开源、免费&#xff08;MIT license&#xff09;的一个小而快并且功能强大的 Windows 动态桌面软件&#xff0c;支持视频和网页动画播放&#xff1a;DreamScene2。 …...

jsp计算机线上教学系统Myeclipse开发mysql数据库web结构java编程计算机网页项目

一、源码特点 JSP 计算机线上教学系统是一套完善的java web信息管理系统&#xff0c;对理解JSP java编程开发语言有帮助&#xff0c;系统具有完整的源代码和数据库&#xff0c;系统主要采用B/S模式开发。开发环境为 TOMCAT7.0,Myeclipse8.5开发&#xff0c;数据库为Mysql5…...

RabbitMQ的高可用机制

RabbitMQ通过多种机制提供高可用性(HA)支持&#xff0c;以确保消息系统的稳定性和可靠性。下面将详细介绍这些机制&#xff0c;并提供代码示例。 集群&#xff08;Clustering&#xff09; RabbitMQ的集群提供了高可用性和负载均衡。集群中的节点共享同一个Erlang分布式数据库…...

人机协同中的贝叶斯和马尔可夫

人机协同中的马尔可夫链是指在人与机器之间协同工作过程中&#xff0c;可能涉及到的状态转移概率模型。马尔可夫链是一种数学模型&#xff0c;描述了在给定当前状态下&#xff0c;未来状态的概率分布只依赖于当前状态&#xff0c;而与过去状态无关的随机过程。在人机协同工作中…...

STM32的SDIO

一.SDIO简介 SDIO&#xff0c;全称Secure Digital Input/Output&#xff0c;是一种用于在移动设备和嵌入式系统中实现输入/输出功能的接口标准。它结合了SD卡的存储功能和I/O功能&#xff0c;允许设备通过SD卡槽进行数据输入输出和外围设备连接。 SDIO接口通常被用于连接各种…...

Unity中的Lerp插值的使用

Unity中的Lerp插值使用 前言Lerp是什么如何使用Lerp 前言 平时在做项目中插值的使用避免不了&#xff0c;之前一直在插值中使用存在误区&#xff0c;在这里浅浅记录一下。之前看的博客或者教程还多都存在一个“永远到达不了&#xff0c;只能无限接近”的一个概念。可能是之前脑…...

年后上来面了一个来字节要求月薪23K,明显感觉他背了很多面试题...

最近有朋友去字节面试&#xff0c;面试前后进行了20天左右&#xff0c;包含4轮电话面试、1轮笔试、1轮主管视频面试、1轮hr视频面试。 据他所说&#xff0c;80%的人都会栽在第一轮面试&#xff0c;要不是他面试前做足准备&#xff0c;估计都坚持不完后面几轮面试。 其实&…...

观成科技:隐蔽隧道工具Ligolo-ng加密流量分析

1.工具介绍 Ligolo-ng是一款由go编写的高效隧道工具&#xff0c;该工具基于TUN接口实现其功能&#xff0c;利用反向TCP/TLS连接建立一条隐蔽的通信信道&#xff0c;支持使用Let’s Encrypt自动生成证书。Ligolo-ng的通信隐蔽性体现在其支持多种连接方式&#xff0c;适应复杂网…...

大语言模型如何处理长文本?常用文本分割技术详解

为什么需要文本分割? 引言:为什么需要文本分割?一、基础文本分割方法1. 按段落分割(Paragraph Splitting)2. 按句子分割(Sentence Splitting)二、高级文本分割策略3. 重叠分割(Sliding Window)4. 递归分割(Recursive Splitting)三、生产级工具推荐5. 使用LangChain的…...

使用van-uploader 的UI组件,结合vue2如何实现图片上传组件的封装

以下是基于 vant-ui&#xff08;适配 Vue2 版本 &#xff09;实现截图中照片上传预览、删除功能&#xff0c;并封装成可复用组件的完整代码&#xff0c;包含样式和逻辑实现&#xff0c;可直接在 Vue2 项目中使用&#xff1a; 1. 封装的图片上传组件 ImageUploader.vue <te…...

HBuilderX安装(uni-app和小程序开发)

下载HBuilderX 访问官方网站&#xff1a;https://www.dcloud.io/hbuilderx.html 根据您的操作系统选择合适版本&#xff1a; Windows版&#xff08;推荐下载标准版&#xff09; Windows系统安装步骤 运行安装程序&#xff1a; 双击下载的.exe安装文件 如果出现安全提示&…...

uniapp微信小程序视频实时流+pc端预览方案

方案类型技术实现是否免费优点缺点适用场景延迟范围开发复杂度​WebSocket图片帧​定时拍照Base64传输✅ 完全免费无需服务器 纯前端实现高延迟高流量 帧率极低个人demo测试 超低频监控500ms-2s⭐⭐​RTMP推流​TRTC/即构SDK推流❌ 付费方案 &#xff08;部分有免费额度&#x…...

Python如何给视频添加音频和字幕

在Python中&#xff0c;给视频添加音频和字幕可以使用电影文件处理库MoviePy和字幕处理库Subtitles。下面将详细介绍如何使用这些库来实现视频的音频和字幕添加&#xff0c;包括必要的代码示例和详细解释。 环境准备 在开始之前&#xff0c;需要安装以下Python库&#xff1a;…...

css3笔记 (1) 自用

outline: none 用于移除元素获得焦点时默认的轮廓线 broder:0 用于移除边框 font-size&#xff1a;0 用于设置字体不显示 list-style: none 消除<li> 标签默认样式 margin: xx auto 版心居中 width:100% 通栏 vertical-align 作用于行内元素 / 表格单元格&#xff…...

Maven 概述、安装、配置、仓库、私服详解

目录 1、Maven 概述 1.1 Maven 的定义 1.2 Maven 解决的问题 1.3 Maven 的核心特性与优势 2、Maven 安装 2.1 下载 Maven 2.2 安装配置 Maven 2.3 测试安装 2.4 修改 Maven 本地仓库的默认路径 3、Maven 配置 3.1 配置本地仓库 3.2 配置 JDK 3.3 IDEA 配置本地 Ma…...

嵌入式学习笔记DAY33(网络编程——TCP)

一、网络架构 C/S &#xff08;client/server 客户端/服务器&#xff09;&#xff1a;由客户端和服务器端两个部分组成。客户端通常是用户使用的应用程序&#xff0c;负责提供用户界面和交互逻辑 &#xff0c;接收用户输入&#xff0c;向服务器发送请求&#xff0c;并展示服务…...

【从零学习JVM|第三篇】类的生命周期(高频面试题)

前言&#xff1a; 在Java编程中&#xff0c;类的生命周期是指类从被加载到内存中开始&#xff0c;到被卸载出内存为止的整个过程。了解类的生命周期对于理解Java程序的运行机制以及性能优化非常重要。本文会深入探寻类的生命周期&#xff0c;让读者对此有深刻印象。 目录 ​…...