C语言实现通讯录
咱们手机上面还有教务系统上都可以存储信息,这些都是使用编程语言来实现的,那么今天,咱们今天就用C语言来实现通讯录。
一. 实验名称
通讯录
二. 实验目标
1.数据的储存
2.数据的增加
3.数据的删除
4.数据的修改
5.数据的展示
6.数据的保存
7.数据的排序
三. 实现的方法
首先,咱们需要一个头文件用来包括数据类型的定义,函数声明,以及所需要使用函数的头文件,然后还需要一个.c文件用来存放所有函数的定义,不然使得主函数所在的.c文件过于冗杂。
test.c(即主函数所在的文件)
#include "test.h"void menu() {printf("*****************************\n");printf("****1.add 2.del ****\n");printf("****3.search 4.modify ****\n");printf("****5.show 6.sort ****\n");printf("****0.exit ****\n");printf("*****************************\n"); }enum option {EXIT,//0ADD,//1DEL,//2SEARCH,MODIFY,SHOW,SORT };int main() {int input = 0;//创建通讯录并将其初始化Contact con;//创建Init_Contact(&con);//将通讯录初始化do{menu();printf("请输入那要选择的操作:");scanf("%d", &input);switch (input){case ADD:Add_Contact(&con);break;case DEL:Del_Contact(&con);break;case SEARCH:Search_Contact(&con);break;case MODIFY:Modify_Contact(&con);break;case SHOW:Show_Contact(&con);break;case SORT:Sort_Contact(&con);break;case EXIT:Save_Contact(&con);Destroy_Contact(&con);printf("退出通讯录!\n");break;default:printf("输入错误,请重新选择!\n");break;}} while (input);return 0; }
为什么上面采用了枚举类型(后续博客会讲到的),因为第一个枚举数默认为0,后面每一个元素都是往后加一,这个Contact con是一个结构体类型(后续博客会讲到的)我们会在头文件中定义。
test.h(即对于函数的声明,结构体定义)
#define _CRT_SECURE_NO_WARNINGS 1 #include <string.h> #include <stdlib.h> #include <assert.h> #include <stdio.h> #pragma once #define NAME_MAX 20 #define SEX_MAX 5 #define TELE_MAX 11 #define NUMBER_MAX 8 #define SZ 3 #define ADD_SZ 2//定义一个结构体类型,存放通讯录人物的基本信息 typedef struct PeoInfo {char name[NAME_MAX];int age;char sex[SEX_MAX];char tele[TELE_MAX];char number[NUMBER_MAX]; }PeoInfo;//定义一个结构体类型,存放通讯录的信息 typedef struct Contact {PeoInfo* data;//结构体类型,用于存储通讯录人物信息int sz;//当前已经存放的信息的个数int capacity;//内存空间大小 }Contact;//函数声明(初始化通讯录) void Init_Contact(Contact* pc);//函数声明(增加通讯录信息) void Add_Contact(Contact* pc);//函数声明(删除通讯录信息) void Del_Contact(Contact* pc);//函数声明(查找通讯录信息) void Search_Contact(const Contact* pc);//函数声明(更改通讯录信息) void Modify_Contact(Contact* pc);//函数声明(展示通讯录信息) void Show_Contact(Contact* pc);//函数声明(排序通讯录) void Sort_Contact(Contact* pc);//函数声明(存储通讯录) void Save_Contact(Contact* pc);//函数声明(销毁通讯录) void Destroy_Contact(Contact* pc);//函数声明(加载通讯录) void Load_Contact(Contact* pc);
这里的结构体类型后续博客会详细的讲解。
contact.h(函数定义)
#include "test.h" //信息初始化 void Init_Contact(Contact* pc) {assert(pc);pc->sz = 0;PeoInfo* ptr = (PeoInfo*)calloc(SZ, sizeof(PeoInfo));if (ptr == NULL){perror("Init_Contact::calloc");return;}pc->data = ptr;pc->capacity = SZ;//加载文件到通讯录Load_Contact(pc); } //检查容量 void Check_Capacity(Contact* pc) {if (pc->capacity == pc->sz)//此时容量与已存入数据相同,这时需要增容{PeoInfo* ptr = realloc(pc->data, ((pc->capacity) + ADD_SZ) * sizeof(PeoInfo));if (ptr == NULL){perror("Check_Capacity;;realloc");return;}pc->data = ptr;pc->capacity += ADD_SZ;printf("增容成功!\n");} } //增加信息 void Add_Contact(Contact* pc) {assert(pc);//检查是否容量已满,已满则选择扩容Check_Capacity(pc);//增加一个新的信息printf("请输入名字:");scanf("%s", pc->data[pc->sz].name);printf("请输入年龄:");scanf("%d", &pc->data[pc->sz].age);printf("请输入性别:");scanf("%s", pc->data[pc->sz].sex);printf("请输入电话:");scanf("%s", pc->data[pc->sz].tele);printf("请输入学号:");scanf("%s", pc->data[pc->sz].number);//信息个数加一pc->sz++; } //查找删除人姓名 int Find_Name(Contact* pc, char name[]) {assert(pc);int i = 0;for (i = 0; i < pc->sz; i++){if (strcmp(pc->data[i].name, name[i]) == 0){return i;}}return -1; } //删除信息 void Del_Contact(Contact* pc) {assert(pc);char name[NAME_MAX] = { 0 };if (pc->sz == 0){printf("通讯录为空,无法删除!\n");return;}//删除printf("请输入你要删除人的姓名:");scanf("%s", name);int ret = Find_Name(pc,name);if (-1 == ret){printf("你要删除的人不存在!\n");return;}int i = 0;for (i = ret; i < pc->sz-1; i++){pc->data[i] = pc->data[i + 1];}pc->sz--;printf("删除成功!\n"); } //查找信息 void Search_Contact(const Contact* pc) {assert(pc);char name[NAME_MAX] = { 0 };printf("请输入你查找人的姓名:");scanf("%s",name);int tmp = Find_Name(pc,name);if (-1 == tmp){printf("你要查找的人不存在!\n");return;}printf("%-20s\t%-4s\t%-5s\t%-11s\t%-8s\n", "名字", "年龄", "性别", "电话", "学号");printf("%-20s\t%-4d\t%-5s\t%-11s\t%-8s\n", pc->data [tmp].name ,pc->data[tmp].age,pc->data[tmp].sex, pc->data[tmp].tele, pc->data[tmp].number); } //更改信息 void Modify_Contact(Contact* pc) {assert(pc);char name[NAME_MAX] = { 0 };printf("请输入你更改人的姓名:");scanf("%s", name);int pos = Find_Name(pc, name);if (-1 == pos){printf("你要更改的人不存在!\n");return;}//更改printf("请输入更改的名字:");scanf("%s", pc->data[pos].name);printf("请输入更改的年龄:");scanf("%d", &pc->data[pos].age);printf("请输入更改的性别:");scanf("%s", pc->data[pos].sex);printf("请输入更改的电话:");scanf("%s", pc->data[pos].tele);printf("请输入更改的学号:");scanf("%s", pc->data[pos].number);printf("修改完成!\n"); } //展示信息 void Show_Contact(Contact* pc) {assert(pc);int i = 0;printf("%-20s\t%-4s\t%-5s\t%-11s\t%-8s\n", "名字", "年龄", "性别", "电话", "学号");printf("%-20s\t%-4d\t%-5s\t%-11s\t%-8s\n", pc->data[i].name,pc->data[i].age,pc->data[i].sex,pc->data[i].tele,pc->data[i].number); } //比较名字大小 int cmp_name(const void* n1, const void* n2) {return (strcmp(((PeoInfo*)n1)->name, ((PeoInfo*)n2)->name)); } //排序通讯录 void Sort_Contact(Contact* pc) {assert(pc);qsort(pc->data, pc->sz, sizeof(PeoInfo), cmp_name);printf("排序完成!\n"); } //储存数据 void Save_Contact(Contact* pc) {FILE* pf = fopen("contact.txt", "wb");if (NULL == pf){perror("Save_Contact");}else{int i = 0;for (i = 0; i < pc->sz; i++){fwrite(pc->data + i, sizeof(PeoInfo), 1, pf);}}fclose(pf);pf = NULL;printf("保存成功!\n"); } // void Load_Contact(Contact* pc) {FILE* pf = fopen("contact.txt", "rb");if (pf == NULL){perror("Load_Contact");}else{PeoInfo tmp = { 0 };int i = 0;while (fread(&tmp, sizeof(PeoInfo), 1, pf)){Check_Capacity(pc);pc->data[i] = tmp;pc->sz++;i++;}fclose(pf);pf = NULL;} } //销毁信息 void Destroy_Contact(Contact* pc) {free(pc->data);pc->data = NULL;pc->sz = 0;pc->capacity = 0;pc = NULL; }
这段代码很长,接下来我们将一一介绍:
assert函数,就是断言,用于判断传入指针是否为空指针,
calloc函数,为创建空间的函数,并会初始化,与melloc还是有略微差异的,
perror函数,查看函数错误的原因并打印出错误信息,
realloc函数,在原有空间上增加空间,
FILE文档类型,
fopen,以某种方式打开文档,
fclose,关闭文档,并且需要将其置位空指针,
free,释放空间函数创建的空间,也需要将其置位空,
这些就是我们所使用的数组,下面就要介绍我们是如何实现的了。
根据主函数我们所需要的功能有增加,删除,展示,排序,查找,展示,保存退出,首先我们需要一个通讯录,一个通讯录需要数据(data),容量(capacity)还有大小(size),并且需要将其初始化,当容量满了之后就需要扩容,增加就只需要让数据的容量内存都变大一个相应的值,非常容易实现,删除,更改和查找都需要先找到所需要元素的名字,找到直接删除,更改即可,展示通讯录使用遍历即可,排序我们则采用qsort快排来实现,最后存储文件我们在后续博客中会讲到,这就是通讯录的全部思路。
相关文章:
C语言实现通讯录
咱们手机上面还有教务系统上都可以存储信息,这些都是使用编程语言来实现的,那么今天,咱们今天就用C语言来实现通讯录。 一. 实验名称 通讯录 二. 实验目标 1.数据的储存 2.数据的增加 3.数据的删除 4.数据的修改 5.数据的展示 6.数据…...

Python-生成列表
1.生成列表使用列表前必须先生成列表。1.1使用运算符[ ]生成列表在运算符[ ]中以逗号隔开各个元素会生成包含这些元素的新列表。另外,如果[ ]中没有元素就会生成空列表示例>>> list01 [] >>> list01 [] >>> list02 [1, 2, 3] >>…...

如何写好controller层
前言本篇主要要介绍的就是controller层的处理,一个完整的后端请求由4部分组成:1. 接口地址(也就是URL地址)、2. 请求方式(一般就是get、set,当然还有put、delete)、3. 请求数据(request,有head跟body)、4. 响应数据(response)本篇…...
MySQL---视图的概念与操作
MySQL—视图的概念与操作 常见的数据库对象 对象描述表(TABLE)表是存储数据的逻辑单元,以行和列的形式存在,列就是字段,行就是记录数据字典就是系统表,存放数据库相关信息的表。系统表的数据通常由数据库系统维护, 程…...

ChatGPT,会是现实世界的MOSS吗?
最近,两个人工智能系统彻底火出了圈,成为许多网友热议的焦点。 一个是冷酷无情的“幕后主角”MOSS,一个是多才多艺的“全能网友”ChatGPT。 先来说说MOSS。今年春节档,科幻电影《流浪地球2》热映,电影中一个面试环节令…...
安卓大厂面试题_安卓开发面经_Android大厂面经(22/30)之JNI全解析
系列专栏: 《150道安卓常见面试题全解析》 安卓专栏目录见帖子 : 安卓面经_anroid面经_150道安卓常见基础面试题全解析 安卓系统Framework面经专栏:《Android系统Framework面试题解析大全》 安卓系统Framework面经目录详情:Android系统面经_Framework开发面经_150道面试题答…...

记一次docker虚拟机横向移动渗透测试
本次渗透在几个docker虚拟机间多次横向移动,最终找到了一个可以进行docker逃逸的出口,拿下服务器。渗透过程曲折但充满了乐趣,入口是172.17.0.6的docker虚拟机,然后一路横向移动,最终在172.17.0.2出实现了docker逃逸&a…...

计算机网络-物理层
计算机网络-物理层 计算机网络学习笔记 学习视频:https://www.bilibili.com/video/BV1c4411d7jb/?p14&spm_id_from333.1007.top_right_bar_window_history.content.click&vd_source75dce036dc8244310435eaf03de4e330 物理层的基本概念 物理层考虑的是怎样…...

Kubernetes Nginx 发布
kubernetes发布nginx 目录 Nginx Pod启动Service访问Nginx 2.1. NodePort访问Nginx 2.2. ClusterIP访问Nginx 2.3. LoadBalancer访问Nginx 2.4. ExternalName访问NginxDeployment方式部署Nginx 3.1 Nginx Replicas Nginx Pod 启动 nginx-v1.yaml apiVersion: v1 kind: Pod…...
华为OD机试真题Python实现【非严格递增连续数字序列】真题+解题思路+代码(20222023)
非严格递增连续数字序列 题目 输入一个字符串仅包含大小写字母和数字 求字符串中包含的最长的非严格递增连续数字序列长度 比如: 12234 属于非严格递增数字序列 🔥🔥🔥🔥🔥👉👉👉👉👉👉 华为OD机试(Python)真题目录汇总 ## 输入 输入一个字符串仅…...
12-render函数
render函数 一、render的作用 非单文件组件时,创建vm的写法: new Vue({el: #root,template: <App></App>,components: {App} })但是该写法在脚手架中会报错。因为脚手架默认引入的是个残缺版的vue。 如果要避免报错,有2种解决…...

磨金石教育摄影技能干货分享|杨元惺佳作欣赏——诗意人文
一般来说,人文摄影总会体现现实性多些。但杨老师是个摄影诗人,他的内心总能将刻板的现实融入美好的光芒。你在他的照片里,看着现实的摄影素材,所感受到的是诗意的绵绵未尽。春网(中国)正所谓春水碧于天&…...

在Pandas中通过时间频率来汇总数据的三种常用方法
当我们的数据涉及日期和时间时,分析随时间变化变得非常重要。Pandas提供了一种方便的方法,可以按不同的基于时间的间隔(如分钟、小时、天、周、月、季度或年)对时间序列数据进行分组。 在Pandas中,有几种基于日期对数据进行分组的方法。我们将…...

基于SPI的增强式插件框架设计
很久之前,为了诊断线上的问题,就想要是能有工具可以在线上出问题的时候,放个诊断包进去马上生效,就能看到线上问题的所在,那该是多么舒服的事情。后来慢慢的切换到 java 领域后,这种理想也变成了现实&#…...

176、【动态规划】leetcode ——1143. 最长公共子序列(C++版本)
题目描述 原题链接:1143. 最长公共子序列 题目描述 本题和 718. 最长重复子数组(动态规划) 的区别在于此时不要求令一个数组中元素连续。 动态规划五步曲: (1)dp[i][j]含义: 截止到text1[i …...

16行代码采集原神官网角色全图+全语音
嗨害大家好鸭!我是小熊猫~ 本来是不玩原神的, 但是实在是经不住诱惑鸭~ 毕竟谁能拒绝可以爬树、炸鱼、壶里造房子、抓小动物、躲猫猫的对战游戏捏~ 准备工具 源码资料电子书:点击此处跳转文末名片获取 准备模块 import requests import re import ex…...

Unity(二)--通过简单例子了解UGUI几个常用对象操作(Text,Image,Button)
目录 文本框等UI对象的添加Canvas 画布给Canvas添加脚本,绑定要操作的对象文本框Text的使用图像Image的使用更换图片Type:显示图片相关按钮Button的使用过渡导航事件绑定文本框等UI对象的添加 Canvas 画布 所有的UI元素的父物体,。 当创建一个UI元素的时候,如果没有Canvas…...

手写一个文件上传demo
背景 最近闲来无事,同事闻了一下上传文件的基本操作,如何用文件流来实现一个文件的上传功能 基本概念 流(Stream)是指在计算机的输入输出操作中各部件之间的数据流动。可以按照数据传输的方向,将流可分为输入流和输出…...

通过 Apifox Echo 了解 Content-Length
Content-Length 用以指定 Body 的体积。响应头中的 Content-Length 指定 Response Body 的体积,请求头中的 Content-Length 指定 Request Body 的体积。 通过 Content-Length,HTTP 客户端/服务器端将会根据该头部计算出 Body 的大小。 请求头中的 Cont…...
ESP32设备驱动-CPU频率设置
CPU频率设置 文章目录 CPU频率设置1、ESP32的CPU频率介绍1.1 CPU时钟1.2 外设时钟2、CPU频率设置API3、软件准备4、硬件准备5、CPU频率设置实例5.1 CPU频率读取5.2 CPU频率设置在本文中,将介绍如何通过Arduino Core设置或更改ESP32 CPU时钟速度(频率)。 1、ESP32的CPU频率介…...

使用docker在3台服务器上搭建基于redis 6.x的一主两从三台均是哨兵模式
一、环境及版本说明 如果服务器已经安装了docker,则忽略此步骤,如果没有安装,则可以按照一下方式安装: 1. 在线安装(有互联网环境): 请看我这篇文章 传送阵>> 点我查看 2. 离线安装(内网环境):请看我这篇文章 传送阵>> 点我查看 说明:假设每台服务器已…...
云计算——弹性云计算器(ECS)
弹性云服务器:ECS 概述 云计算重构了ICT系统,云计算平台厂商推出使得厂家能够主要关注应用管理而非平台管理的云平台,包含如下主要概念。 ECS(Elastic Cloud Server):即弹性云服务器,是云计算…...
模型参数、模型存储精度、参数与显存
模型参数量衡量单位 M:百万(Million) B:十亿(Billion) 1 B 1000 M 1B 1000M 1B1000M 参数存储精度 模型参数是固定的,但是一个参数所表示多少字节不一定,需要看这个参数以什么…...
在HarmonyOS ArkTS ArkUI-X 5.0及以上版本中,手势开发全攻略:
在 HarmonyOS 应用开发中,手势交互是连接用户与设备的核心纽带。ArkTS 框架提供了丰富的手势处理能力,既支持点击、长按、拖拽等基础单一手势的精细控制,也能通过多种绑定策略解决父子组件的手势竞争问题。本文将结合官方开发文档,…...
TRS收益互换:跨境资本流动的金融创新工具与系统化解决方案
一、TRS收益互换的本质与业务逻辑 (一)概念解析 TRS(Total Return Swap)收益互换是一种金融衍生工具,指交易双方约定在未来一定期限内,基于特定资产或指数的表现进行现金流交换的协议。其核心特征包括&am…...

微信小程序云开发平台MySQL的连接方式
注:微信小程序云开发平台指的是腾讯云开发 先给结论:微信小程序云开发平台的MySQL,无法通过获取数据库连接信息的方式进行连接,连接只能通过云开发的SDK连接,具体要参考官方文档: 为什么? 因为…...
聊一聊接口测试的意义有哪些?
目录 一、隔离性 & 早期测试 二、保障系统集成质量 三、验证业务逻辑的核心层 四、提升测试效率与覆盖度 五、系统稳定性的守护者 六、驱动团队协作与契约管理 七、性能与扩展性的前置评估 八、持续交付的核心支撑 接口测试的意义可以从四个维度展开,首…...

技术栈RabbitMq的介绍和使用
目录 1. 什么是消息队列?2. 消息队列的优点3. RabbitMQ 消息队列概述4. RabbitMQ 安装5. Exchange 四种类型5.1 direct 精准匹配5.2 fanout 广播5.3 topic 正则匹配 6. RabbitMQ 队列模式6.1 简单队列模式6.2 工作队列模式6.3 发布/订阅模式6.4 路由模式6.5 主题模式…...

R语言速释制剂QBD解决方案之三
本文是《Quality by Design for ANDAs: An Example for Immediate-Release Dosage Forms》第一个处方的R语言解决方案。 第一个处方研究评估原料药粒径分布、MCC/Lactose比例、崩解剂用量对制剂CQAs的影响。 第二处方研究用于理解颗粒外加硬脂酸镁和滑石粉对片剂质量和可生产…...

三分算法与DeepSeek辅助证明是单峰函数
前置 单峰函数有唯一的最大值,最大值左侧的数值严格单调递增,最大值右侧的数值严格单调递减。 单谷函数有唯一的最小值,最小值左侧的数值严格单调递减,最小值右侧的数值严格单调递增。 三分的本质 三分和二分一样都是通过不断缩…...