自定义类型详解(2)

文章目录

    • 5. 通讯录的实现

5. 通讯录的实现

实现一个通讯录:

通讯录中保存人的信息:

  • 名字
  • 年龄
  • 性别
  • 电话
  • 住址
  1. 通讯录中可以存放100个人的信息
  2. 增加联系人
  3. 删除指定联系人
  4. 修改指定联系人
  5. 查找指定联系人
  6. 显示所有联系人的信息
  7. 排序功能

首先,我们需要三个文件:

  • test.c - 测试通讯录
  • contact.h - 函数和类型的声明
  • contact.c - 函数的实现

设计保存人的信息的这个结构体:

//contact.h//类型的声明typedef struct PeoInfo
{char name[20];int age;char sex[5];char tele[12];char addr[30];
}PeoInfo;

接着,我们实现一下大体逻辑:

//test.cvoid 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");
}void test()
{int input = 0;do{menu();printf("请选择:>");scanf("%d", &input);switch (input){case 1:break;case 2:break;case 3:break;case 4:break;case 5:break;case 6:break;case 0:break;default:break;}} while (input);
}int main()
{test();return 0;
}

我们要实现通讯录的各项功能,首先要有通讯录:一个 PeoInfo 类型的数组,但是我们再思考一下,如果我们要添加联系人,那么我们是不是需要一个变量来统计通讯录中一共有多少个人,所以还需要一个整型变量。

//contact.h//通讯录typedef struct Contact
{PeoInfo data[100];int sz;
}Contact;
//test.c#include "contact.h"void test()
{//首先得有通讯录Contact con;
}

对通讯录进行初始化:

//contact.h#include <string.h>
#include <assert.h>//函数声明//初始化通讯录
void InitContact(Contact* pc);
//contact.c#include "contact.h"void InitContact(Contact* pc)
{	assert(pc);memset(pc->data, 0, sizeof(pc->data));pc->sz = 0;
}
//test.cvoid test()
{InitContact(&con);
}

注:
传参时传的是地址,有以下两点原因:

  1. 要改变实参的值,就要传地址过去
  2. 根据之前对结构体的学习,结构体一般传地址,因为传整个结构体要开辟的内存空间太大了

增加联系人:

//contact.h//增加联系人
void AddContact(Contact* pc);
//contact.cvoid AddContact(Contact* pc)
{	if (100 == pc->sz){printf("通讯录已满,无法添加\n");return;}
}

我们发现前面创建data数组时用到了100,这里也用到了100,之后如果要修改值,两处都要改,那么我们应该如何简化它呢?

//contact.h#define MAX 100
#define MAX_NAME 20
#define MAX_SEX 5
#define MAX_TELE 12
#define MAX_ADDR 30enum OPTION
{EXIT,//0ADD,DEL,SEARCH,MODIFY,SHOW,SORT
};//类型的声明typedef struct PeoInfo
{char name[MAX_NAME];int age;char sex[MAX_SEX];char tele[MAX_TELE];char addr[MAX_ADDR];
}PeoInfo;//通讯录typedef struct Contact
{PeoInfo data[MAX];int sz;
}Contact;
//contact.cvoid AddContact(Contact* pc)
{	assert(pc);if (MAX == pc->sz){printf("通讯录已满,无法添加\n");return;}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].addr);pc->sz++;printf("成功增加联系人\n");
}
//test.cvoid test()
{int input = 0;//首先得有通讯录Contact con;InitContact(&con);do{menu();printf("请选择:>");scanf("%d", &input);switch (input){case ADD:AddContact(&con);break;case DEL:break;case SEARCH:break;case MODIFY:break;case SHOW:break;case SORT:break;case EXIT:break;default:break;}} while (input);
}

显示联系人:

//contact.h//显示所有联系人的信息
void ShowContact(const Contact* pc);
//contact.cvoid ShowContact(const Contact* pc)
{assert(pc);int i = 0;//打印列标题printf("%-20s\t%-4s\t%-5s\t%-12s\t%-30s\n", "名字", "年龄", "性别", "电话", "地址");//打印数据for (i = 0; i < pc->sz; i++){printf("%-20s\t%-4d\t%-5s\t%-12s\t%-30s\n",pc->data[i].name,pc->data[i].age,pc->data[i].sex,pc->data[i].tele,pc->data[i].addr);}}

删除指定联系人:

//contact.h//删除指定联系人
void DelContact(Contact* pc);
//contact.cvoid DelContact(Contact* pc)
{assert(pc);if (0 == pc->sz){printf("通讯录为空,无法删除\n");return;}char name[MAX_NAME] = { 0 };//删除printf("请输入要删除的人的名字:>");scanf("%s", name);//找到要删除的人int i = 0;int del = 0;int flag = 0;for (i = 0; i < pc->sz; i++){if (0 == strcmp(pc->data[i].name, name)){del = i;flag = 1;break;}}if (0 == flag){printf("要删除的人不存在\n");return;}//删除坐标为del的联系人for (i = del; i < pc->sz - 1; i++){pc->data[i] = pc->data[i + 1];}pc->sz--;printf("成功删除联系人\n");
}

但是这个代码有一些缺陷:我们可以发现我们要实现的查找联系人和修改联系人这两个功能同样也需要先进行查找,因此我们可以对查找联系人的这一代码块进行分装,让它单独作为一个函数。

//contact.cstatic int FindByName(const Contact* pc, char name[])
{int i = 0;for (i = 0; i < pc->sz; i++){if (0 == strcmp(pc->data[i].name, name)){return i;//找到了}}return -1;//找不到
}void DelContact(Contact* pc)
{assert(pc);if (0 == pc->sz){printf("通讯录为空,无法删除\n");return;}char name[MAX_NAME] = { 0 };//删除printf("请输入要删除的人的名字:>");scanf("%s", name);//找到要删除的人int del = FindByName(pc, name);if (-1 == del){printf("要删除的人不存在\n");return;}int i = 0;//删除坐标为del的联系人for (i = del; i < pc->sz - 1; i++){pc->data[i] = pc->data[i + 1];}pc->sz--;printf("成功删除联系人\n");
}

查找指定联系人:

//contact.h//查找指定联系人
void SearchContact(const Contact* pc);
//contact.cvoid SearchContact(const Contact* pc)
{assert(pc);char name[MAX_NAME] = { 0 };printf("请输入要查找人的名字:>");scanf("%s", name);int pos = FindByName(pc, name);if (-1 == pos){printf("要查找的人不存在\n");}else{//打印列标题printf("%-20s\t%-4s\t%-5s\t%-12s\t%-30s\n", "名字", "年龄", "性别", "电话", "地址");//打印数据printf("%-20s\t%-4d\t%-5s\t%-12s\t%-30s\n",pc->data[pos].name,pc->data[pos].age,pc->data[pos].sex,pc->data[pos].tele,pc->data[pos].addr);}
}

修改指定联系人:

//contact.h//修改指定联系人
void ModifyContact(Contact* pc);
//contact.cvoid ModifyContact(Contact* pc)
{assert(pc);char name[MAX_NAME] = { 0 };printf("请输入要修改人的名字:>");scanf("%s", name);int pos = FindByName(pc, name);if (-1 == pos){printf("要修改的人不存在\n");}else{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].addr);printf("修改成功\n");}
}

排序功能:

我们可以按照名字排序,也可以按照年龄排序。

//contact.henum SELECT
{NAME = 1,AGE
};//排序功能
void SortContact(Contact* pc);
//contact.cvoid select()
{printf("********************************\n");printf("***** 1. name    2. age    *****\n");printf("********************************\n");
}int cmp_by_name(const void* p1, const void* p2)
{return strcmp(((PeoInfo*)p1)->name, ((PeoInfo*)p2)->name);
}int cmp_by_age(const void* p1, const void* p2)
{return ((PeoInfo*)p1)->age - ((PeoInfo*)p2)->age;
}void SortContact(Contact* pc)
{assert(pc);if (0 == pc->sz){printf("通讯录为空,无法排序\n");return;}int input = 0;do{select();printf("请选择按何种方式进行排序:>");scanf("%d", &input);switch (input){case NAME:qsort(pc->data, pc->sz, sizeof(pc->data[0]), cmp_by_name);printf("排序成功\n");break;case AGE:qsort(pc->data, pc->sz, sizeof(pc->data[0]), cmp_by_age);printf("排序成功\n");break;default:printf("选择错误,重新选择\n");break;}} while (input != 1 && input != 2);
}

完整代码:

//contact.h#include <string.h>
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>#define MAX 100
#define MAX_NAME 20
#define MAX_SEX 5
#define MAX_TELE 12
#define MAX_ADDR 30enum OPTION
{EXIT,//0ADD,DEL,SEARCH,MODIFY,SHOW,SORT
};enum SELECT
{NAME = 1,AGE
};//类型的声明typedef struct PeoInfo
{char name[MAX_NAME];int age;char sex[MAX_SEX];char tele[MAX_TELE];char addr[MAX_ADDR];
}PeoInfo;//通讯录typedef struct Contact
{PeoInfo data[MAX];int sz;
}Contact;//函数声明//初始化通讯录
void InitContact(Contact* pc);//增加联系人
void AddContact(Contact* pc);//显示所有联系人的信息
void ShowContact(const Contact* pc);//删除指定联系人
void DelContact(Contact* pc);//查找指定联系人
void SearchContact(const Contact* pc);//修改指定联系人
void ModifyContact(Contact* pc);//排序功能
void SortContact(Contact* pc);
//contact.c#include "contact.h"void InitContact(Contact* pc)
{assert(pc);memset(pc->data, 0, sizeof(pc->data));pc->sz = 0;
}void AddContact(Contact* pc)
{assert(pc);if (MAX == pc->sz){printf("通讯录已满,无法添加\n");return;}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].addr);pc->sz++;printf("成功增加联系人\n");
}void ShowContact(const Contact* pc)
{assert(pc);int i = 0;//打印列标题printf("%-20s\t%-4s\t%-5s\t%-12s\t%-30s\n", "名字", "年龄", "性别", "电话", "地址");//打印数据for (i = 0; i < pc->sz; i++){printf("%-20s\t%-4d\t%-5s\t%-12s\t%-30s\n",pc->data[i].name,pc->data[i].age,pc->data[i].sex,pc->data[i].tele,pc->data[i].addr);}}static int FindByName(const Contact* pc, char name[])
{int i = 0;for (i = 0; i < pc->sz; i++){if (0 == strcmp(pc->data[i].name, name)){return i;//找到了}}return -1;//找不到
}void DelContact(Contact* pc)
{assert(pc);if (0 == pc->sz){printf("通讯录为空,无法删除\n");return;}char name[MAX_NAME] = { 0 };//删除printf("请输入要删除的人的名字:>");scanf("%s", name);//找到要删除的人int del = FindByName(pc, name);if (-1 == del){printf("要删除的人不存在\n");return;}int i = 0;//删除坐标为del的联系人for (i = del; i < pc->sz - 1; i++){pc->data[i] = pc->data[i + 1];}pc->sz--;printf("成功删除联系人\n");
}void SearchContact(const Contact* pc)
{assert(pc);char name[MAX_NAME] = { 0 };printf("请输入要查找人的名字:>");scanf("%s", name);int pos = FindByName(pc, name);if (-1 == pos){printf("要查找的人不存在\n");}else{//打印列标题printf("%-20s\t%-4s\t%-5s\t%-12s\t%-30s\n", "名字", "年龄", "性别", "电话", "地址");//打印数据printf("%-20s\t%-4d\t%-5s\t%-12s\t%-30s\n",pc->data[pos].name,pc->data[pos].age,pc->data[pos].sex,pc->data[pos].tele,pc->data[pos].addr);}
}void ModifyContact(Contact* pc)
{assert(pc);char name[MAX_NAME] = { 0 };printf("请输入要修改人的名字:>");scanf("%s", name);int pos = FindByName(pc, name);if (-1 == pos){printf("要修改的人不存在\n");}else{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].addr);printf("修改成功\n");}
}void select()
{printf("********************************\n");printf("***** 1. name    2. age    *****\n");printf("********************************\n");
}int cmp_by_name(const void* p1, const void* p2)
{return strcmp(((PeoInfo*)p1)->name, ((PeoInfo*)p2)->name);
}int cmp_by_age(const void* p1, const void* p2)
{return ((PeoInfo*)p1)->age - ((PeoInfo*)p2)->age;
}void SortContact(Contact* pc)
{assert(pc);if (0 == pc->sz){printf("通讯录为空,无法排序\n");return;}int input = 0;do{select();printf("请选择按何种方式进行排序:>");scanf("%d", &input);switch (input){case NAME:qsort(pc->data, pc->sz, sizeof(pc->data[0]), cmp_by_name);printf("排序成功\n");break;case AGE:qsort(pc->data, pc->sz, sizeof(pc->data[0]), cmp_by_age);printf("排序成功\n");break;default:printf("选择错误,重新选择\n");break;}} while (input != 1 && input != 2);
}
//test.c#include "contact.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");
}void test()
{int input = 0;//首先得有通讯录Contact con;InitContact(&con);do{menu();printf("请选择:>");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:printf("退出通讯录\n");break;default:printf("选择错误,重新选择\n");break;}} while (input);
}int main()
{test();return 0;
}

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

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

相关文章

Python爬虫---scrapy框架---下载嵌套数据

./spider/movie.py文件 import scrapy from scrapy_movie_20240116.items import ScrapyMovie20240116Itemclass MovieSpider(scrapy.Spider):name "movie"# 如果是多页下载的话, 那么必须要调整的是allowed_domains的范围 一般情况下只写城名allowed_domains [&…

决战排序之巅(二)

决战排序之巅&#xff08;二&#xff09; 排序测试函数 void verify(int* arr, int n) 归并排序递归方案代码可行性测试 非递归方案代码可行性测试 特点分析 计数排序代码实现代码可行性测试 特点分析 归并排序 VS 计数排序&#xff08;Release版本&#xff09;说明1w rand( ) …

MATLAB - 加载预定义的机器人模型

系列文章目录 前言 一、 要快速访问常见的机器人模型&#xff0c;可使用 loadrobot 功能&#xff0c;该功能可加载市售的机器人模型&#xff0c;如 Universal Robots™ UR10 cobot、Boston Dynamics™ Atlas 人形机器人和 KINOVA™ Gen 3 机械手。探索如何生成关节配置并与机器…

小程序基础库与Android之间通信优化的可能

最近在学习graalvm&#xff0c;发现有一个graaljs项目&#xff0c;项目中介绍可以让java与JavaScript做数据转换&#xff0c;比如JavaScript中可以使用java的数据类型与结构。突然想到之前遇到的一个问题&#xff0c;小程序中开发的代码和基础库的部分代码都是j2v8来执行的&…

深入理解 Spark(二)SparkApplication 提交和运行源码分析

spark 核心流程 yarn-client yarn-cluster spark 任务调度 spark stage 级别调度 spark task 级别调度 失败重试和白名单 对于运行失败的 Task&#xff0c;TaskSetManager 会记录它失败的次数&#xff0c;如果失败次数还没有超过最大重试次数&#xff0c;那么就把它放回待调…

【Docker构建MySQL8.0镜像】

Docker构建MySQL8.0镜像 部署流程1. 拉取docker镜像2. 创建数据卷&#xff0c;存放MySQL数据3. 启动MySQL镜像4. 初始化sql放入MySQL镜像5. 执行MySQL脚本6. MySQL镜像打包7. MySQL镜像迁移 部署流程 1. 拉取docker镜像 docker pull mysql:8.0.35拉取成功后就可以看到镜像了&…

openxml获取sheet所有的数据二维数组

此代码假定您已经安装了OpenXML SDK&#xff0c;并且您有一个.xlsx文件的路径。\n\n请注意&#xff0c;续写的代码将获取指定工作表中的所有数据&#xff0c;包括空单元格&#xff0c;并将它们存储在一个二维数组中。如果工作表中有多个行和列&#xff0c;数组的大小将与工作表…

NFS(Network File System 网络文件服务)

一&#xff0c;nfs 简介 1&#xff0c;nfs 性质 NFS&#xff08;Network File System 网络文件服务&#xff09; 文件系统&#xff08;软件&#xff09;文件的权限 NFS 是一种基于 TCP/IP 传输的网络文件系统协议 通过使用 NFS 协议&#xff0c;客户机可以像访问本地目录一样…

【NI国产替代】NI-9231,8通道,51.2 kS/s/ch,-5至5 V,C系列声音和振动输入模块

8通道&#xff0c;51.2 kS/s/ch&#xff0c;-5至5 V&#xff0c;C系列声音和振动输入模块 NI-9231是一款高密度声音和振动模块&#xff0c;能够测量来自速度计、转速计和接近式探针等集成电子压电(IEPE)和非IEPE传感器的信号。该模块可以执行现代麦克风和加速计所需的高动态范围…

【Java万花筒】未来编码:深度了解Java中机器学习的核心库

构建智能系统&#xff1a;Java中的机器学习库全攻略 前言 随着人工智能和机器学习的不断发展&#xff0c;使用合适的库成为构建强大应用的关键一环。本文将深入介绍几个在Java生态系统中备受推崇的机器学习与人工智能库&#xff0c;为读者提供全面的了解和使用指南。每个库都…

verilog编程题

verilog编程题 文章目录 verilog编程题序列检测电路&#xff08;状态机实现&#xff09;分频电路计数器译码器选择器加减器触发器寄存器 序列检测电路&#xff08;状态机实现&#xff09; module Detect_101(input clk,input rst_n,input data,o…

56.Spring事务:事务四大特性

56.Spring事务&#xff1a;事务四大特性 原子性&#xff08;Atomicity&#xff09; 原子性是指事务包含的所有操作要么全部成功&#xff0c;要么全部失败回滚&#xff0c; 因此事务的操作如果成功就必须要完全应用到数据库&#xff0c;如果操作失败则不能对数据库有任何影响。…

力扣每日一练(24-1-15)

重复n次检查&#xff0c;几乎都用双指针。。。 固然双指针就是题解&#xff1a; if len(nums) < 3:return len(nums)p1 2 for p2 in range(2, len(nums)):if nums[p2] ! nums[p1 - 2]:nums[p1] nums[p2]p1 1return p1 可以重复两次&#xff0c;那么隔一个检查就行&#…

【征服redis3】一文征服redis的jedis客户端

使用数据库的时候&#xff0c;我们可以用JDBC来实现mysql数据库与java程序之间的通信&#xff0c;为了提高通信效率&#xff0c;我们有了数据库连接池比如druid等等。而我们想通过Java程序控制redis&#xff0c;同样可以借助一些工具来实现&#xff0c;这就是redis客户端&#…

npm install 卡住不动的六种解决方法

1.重装 检查网络设置&#xff0c;删除node_modules重新npm install 2. 配置npm代理 // 配置nmp代理来提高速度&#xff0c;如设置淘宝镜像 npm config set registry https://registry.npm.taobao.org// 查看配置是否成功 npm config get registry// 成功后重新npm install安…

vtk9.3 配置 visual studio 2019 运行环境 和运行实例详解

&#xff08;1&#xff09;包含文件配置&#xff1a; 项目--属性--VC目录&#xff0c;在包含目录中把include文件夹的地址加进去&#xff0c;一直要到下一级 vtk-9.3目录下&#xff0c; 小知识&#xff1a; 在Visual Studio 2019中运行项目时&#xff0c;如果项目中使用了第三…

网络安全笔记-SQL注入

文章目录 前言一、数据库1、Information_schema2、相关函数 二、SQL注入分类1、联合查询注入&#xff08;UNION query SQL injection&#xff09;语法 2、报错注入&#xff08;Error-based SQL injection&#xff09;报错注入分类报错函数报错注入原理 3、盲注布尔型盲注&#…

【Java 设计模式】创建型之抽象工厂模式

文章目录 1. 定义2. 应用场景3. 代码实现4. 应用示例结语 在软件开发中&#xff0c;抽象工厂模式是一种常见的创建型设计模式&#xff0c;它提供了一种创建一系列相关或相互依赖对象的接口&#xff0c;而无需指定它们具体的类。抽象工厂模式的核心思想是将一组相关的产品组合成…

docker screen 常用基础命令

1.docker基础命令 1.1开启docker systemctl start docker #开启docker service docker restart #重启docker systemctl stop docker #关闭docker 1.2查看命令 docker images #查看docker镜像docker ps #查看正在运行的镜像或者容器docker ps -a #查看所有容器1.3运…

刘知远LLM入门到实战——自然语言基础

文章目录 自然语言处理基础词表示语言模型N-gram ModelNeural Language Model: 为什么NLP等领域的模型越来越大&#xff1f; 大模型会带来哪些新的范式和挑战&#xff1f; 自然语言处理基础 让计算机理解人类语言&#xff0c;图灵测试就是基于对话的方式。 研究历史&#xff…