C语言结构体练习:【通讯录(静态数组简易版)的实现】

news/2024/9/22 14:40:35/

全文目录

  • 😀 前言
  • 🤔 模块和功能划分
  • 🤨 数据类型的选择
    • 😮 功能序号类型 `enum`
    • 😮 个人信息类型 `PeoInfo`
    • 😮 通讯录类型 `Contact`
  • 😵‍💫 功能的实现
    • 🙄 初始化通讯录 `InitContact`
    • 🙄 添加功能 `AddContact`
    • 🙄 打印功能 `PrintContact`
    • 🙄 删除联系人 `DeleteContact`
      • 😍 通过名字查找对应下标 `FindByName`
    • 🙄 查找联系人 `SearchContact`
    • 🙄 修改联系人信息 `ModifyContact`
    • 🙄 清空通讯录 `EmptyContact`
    • 🙄 排序功能 `SortContact`
  • 🌈 总结

😀 前言

前面我们学习了C语言的结构体等自定义类型的知识,乌泱泱的一大堆知识,没有练习肯定是学不扎实的,所以今天我们将前面学到的所有C语言知识整合起来进行实现一个小项目:通讯录(静态数组简易版),达到一个复习的目的。

🤔 模块和功能划分

我们实现的通讯录主要有以下几个功能:

  1. 退出(exit)
  2. 添加(add)
  3. 删除(delete)
  4. 查找(search)
  5. 修改(modify)
  6. 打印(print)
  7. 清空(empty)
  8. 排序(sort)

同时为了方便调试和代码的美观,我们将代码分为三个源文件:test.c, contact.h, contact.c
通话录模块功能划分

🤨 数据类型的选择

😮 功能序号类型 enum

对于各种功能,在实现的时候是通过switch case 语句来实现各种功能的:

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 7: 	// 排序...break;case 0: 	// 退出...break;default: 	// 输入其他提示错误printf("选择错误\n");}} while (input);

我们可以使用枚举类型将功能和对应的序号关联起来,这样代码的可读性就能大大地提高了:

enum Option 
{EXIT,	// 0ADD,	// 1DELETE, 	// 2SEARCH, 	// 3MODIFY, 	// 4PRINT, 	// 5EMPTY, 	// 6SORT 	// 7
};do {menu();printf("请选择->");scanf("%d", &input);switch (input) {case ADD: 	// 添加...break;case DELETE: 	// 删除...break;case SEARCH: 	// 查找...break;case MODIFY: 	// 修改...break;case PRINT: 	// 打印...break;case EMPTY: 	// 清空...break;case SORT: 	// 排序...break;case EXIT: 	// 退出...break;default: 	// 输入其他提示错误printf("选择错误\n");}} while (input);

😮 个人信息类型 PeoInfo

对于一个人的信息,基本上都是通过字符串来描述,都需要使用字符数组来存放,数组的长度可以使用宏定义来进行替换,方便后期管理。对于每个人的信息我们可以将其定义为结构体:

#define MAX_NAME 20
#define MAX_SEX 3
#define MAX_AGE 3
#define MAX_TELE 12
#define MAX_ADDRS 30typedef struct PeoInform 
{char name[MAX_NAME];char sex[MAX_SEX];char age[MAX_AGE];char telephon[MAX_TELE];char addrs[MAX_ADDRS];
} PeoInform;

😮 通讯录类型 Contact

通讯录的是存放所有人的信息的,那么需要能够存放所有人的信息的空间,我们直接使用数组来实现,因为添加操作的时候我们需要标记哪个位置可以使用,所以需要使用size来记录通讯录的大小。

#define MAX 1000 	// 通讯录人数的上限typedef struct Contact 
{PeoInform data[1000];int size;
} Contact;

😵‍💫 功能的实现

数据的类型确定了,我们就可以来实现各种功能了。

🙄 初始化通讯录 InitContact

由于通讯录是一个结构体,定义出来的又是局部变量,其内容是随机值。所以在使用之前需要先初始化一下,为了后期更好的维护,还是通过函数来进行初始化。

// 初始化
void InitContact(Contact* con)
{assert(con);con->size = 0;memset(con->data, 0, sizeof(con->data));
}

🙄 添加功能 AddContact

因为有了size,所以新加入的联系人可以之间存放在data数组的size位置上。如果

// 添加联系人
void AddContact(Contact* con)
{assert(con);puts("");if (con->size == MAX)	// 满了就不能再添加{puts("通讯录已满!!!");}else{printf("请输入姓名 ->");scanf("%s", con->data[con->size].name);printf("请输入性别 ->");scanf("%s", con->data[con->size].sex);printf("请输入年龄 ->");scanf("%s", con->data[con->size].age);printf("请输入电话号码 ->");scanf("%s", con->data[con->size].telephon);printf("请输入地址 ->");scanf("%s", con->data[con->size].addrs);puts("");con->size++;printf("添加成功!\n");}
}

🙄 打印功能 PrintContact

添加成功后我们可以通过打印功能来进行查看,在参数方面,因为我们只是访问一下数据,所以加上const修饰一下比较好。

// 打印联系人的信息
void PrintContact(const Contact* con)
{assert(con);printf("%-20s %-5s %-5s %-12s %-30s\n","名字", "性别", "年龄", "电话号码", "地址");for (int i = 0; i < con->size; i++) {printf("%-20s %-5s %-5s %-12s %-30s\n", con->data[i].name, con->data[i].sex, con->data[i].age, con->data[i].telephon, con->data[i].addrs);}
}

🙄 删除联系人 DeleteContact

😍 通过名字查找对应下标 FindByName

删除联系人一般是按照名字来进行删除的,所以我们需要先通过名字找到对应的下标再进行删除,因为后面需要查找的功能也需要通过名字来找人,所以这里之间实现一个函数:FindByName

// 通过名字来寻找联系人所在的下标
int FindByName(Contact* con, char* name)
{int i = 0;for (; i < con->size; i++){if (strcmp(con->data[i].name, name) == 0) return i;}return -1;
}

如果通讯录中没有该名字,提示后返回,如果有,找到后通过覆盖的方式进行删除

// 删除指定联系人
void DeleteContact(Contact* con)
{assert(con);puts("");// 1. 找到联系人char name[MAX_NAME] = { 0 };printf("请输入需要删除的联系人的姓名->");scanf("%s", name);int pos = FindByName(con, name);// 2. 覆盖删除联系人if (pos == -1){puts("");puts("无该联系人!!!");}else{for (int i = pos; i < con->size - 1; i++) {con->data[i] = con->data[i + 1];}con->size--;printf("删除成功!\n");}
}

🙄 查找联系人 SearchContact

通过名字查找,找到后直接输出信息,没找到提示后返回

// 查找指定联系人
void SearchContact(const Contact* con)
{assert(con);puts("");// 1. 找到联系人char name[MAX_NAME] = { 0 };printf("请输入需要删除的联系人的姓名->");scanf("%s", name);int pos = FindByName(con, name);if (pos == -1){puts("找不到该联系人???");}else{printf("%-20s %-5s %-5s %-12s %-30s\n","名字", "性别", "年龄", "电话号码", "地址");printf("%-20s %-5s %-5s %-12s %-30s\n",con->data[pos].name, con->data[pos].sex,con->data[pos].age, con->data[pos].telephon,con->data[pos].addrs);}
}

🙄 修改联系人信息 ModifyContact

名字作为关键字来修改个人信息。

// 修改指定联系人信息
void ModifeContact(Contact* con)
{assert(con);puts("");// 1. 找到联系人char name[MAX_NAME] = { 0 };printf("请输入需要删除的联系人的姓名->");scanf("%s", name);int pos = FindByName(con, name);if (pos == -1){puts("找不到该联系人???");}else{printf("请输入姓名 ->");scanf("%s", con->data[pos].name);printf("请输入性别 ->");scanf("%s", con->data[pos].sex);printf("请输入年龄 ->");scanf("%s", con->data[pos].age);printf("请输入电话号码 ->");scanf("%s", con->data[pos].telephon);printf("请输入地址 ->");scanf("%s", con->data[pos].addrs);printf("\n");printf("修改成功!\n");printf("%-20s %-5s %-5s %-12s %-30s\n", "名字", "性别", "年龄", "电话号码", "地址");printf("%-20s %-5s %-5s %-12s %-30s\n", con->data[pos].name, con->data[pos].sex, con->data[pos].age, con->data[pos].telephon, con->data[pos].addrs);}
}

🙄 清空通讯录 EmptyContact

因为全部的访问操作都跟size有关,所以清空时只需要将size置为0即可。

// 清空通讯录
void EmptyContact(Contact* con)
{assert(con);con->size = 0;printf("清空成功!\n");
}

🙄 排序功能 SortContact

还是老样子,用名字作为关键字,这里我使用的是冒泡排序,相对简单一点。

// 通过姓名排序
void SortContact(Contact* con)
{assert(con);for (int i = 0; i < con->size; i ++)for (int j = 0; j < con->size - 1 - i; j++){if (strcmp(con->data[j].name, con->data[j + 1].name) > 0){PeoInform temp = con->data[j];con->data[j] = con->data[j + 1];con->data[j + 1] = temp;}}puts("排序成功");
}

🌈 总结

以上就是第一个版本的通讯录的实现了。看似简单,但是对C语言的基础知识也是有一定的考验的,想要打牢基础还是要多写写联系一下的。

源码地址:静态数组版通讯录


http://www.ppmy.cn/news/43086.html

相关文章

数字孪生之ThingJS

数字孪生对象层级关系获取对象的方法对象层级关系 获取对象的方法 通过加载事件获取根对象&#xff0c;从而去获取子对象app.on("load", function(ev){var campus ev.campus; // 园区对象集合var buildings campus.buildings; // 建筑对象集合// var building…

一位腾讯在职7年测试工程师的心声...

作为一个在腾讯工作7年的测试工程师&#xff0c;今天就来聊聊腾讯工作压力到底从何而来。 压力的开始&#xff1a;时间回到7年前&#xff0c;我人生中的第一份实习工作&#xff0c;是在腾讯公司做一个自动化测试工程师。当时的我可谓意气风发&#xff0c;想要大干一场&#xf…

带你走进Flutter 3.7

期待已久的新教程上线啦&#xff01;解锁Flutter开发新姿势&#xff0c;一网打尽Flutter最新与最热技术&#xff0c;点我Get!!! 新年伊始&#xff0c;由 Flutter 3.7 正式版来「打头阵」&#xff01;我们与整个 Flutter 社区们继续在 Flutter 3.7 中优化了框架&#xff0c;包括…

Java EE企业级应用开发(SSM)第5章

第5章Spring MVC入门一.预习笔记 1.Spring MVC是所有使用OOP编程语言都应该遵守的规范 2.Spring MVC的特点 强大的灵活性、非侵入性和可配置性 提供了一个前端控制器DispatcherServlet&#xff0c;开发者无须额外开发控制器对象 分工明确&#xff0c;每一个功能由一个专门…

rust中的集合容器(切片和哈希)与错误处理

String、数组[T:n]、列表Vec\哈希表HashMap<K,V>等。 切片slice&#xff1b; 循环缓冲区 VecDeque、双向列表 LinkedList等。(这是指双向链表吗&#xff1f;) 这些集合容器的共性&#xff1a; 可以遍历 可以进行 map-reduce操作。 可以从一种类型转换成另一种类型。 主要…

电子招投标系统源码之了解电子招标投标全流程

随着各级政府部门的大力推进&#xff0c;以及国内互联网的建设&#xff0c;电子招投标已经逐渐成为国内主流的招标投标方式&#xff0c;但是依然有很多人对电子招投标的流程不够了解&#xff0c;在具体操作上存在困难。虽然各个交易平台的招标投标在线操作会略有不同&#xff0…

话说~~ HTTP协议请求的工作流程 (Web服务请求过程)最细详解

目录 文章导入 &#xff1a; 概述 &#xff1a; 详解过程 &#xff1a; DNS域名解析 &#xff1a; DNS 域名解析过程分析 &#xff1a; TCP连接搭建 &#xff1a; 等待TCP队列 建立TCP连接 发起 HTTP 请求 &#xff1a; # 哪是如何进行 HTTP 请求的呢 &#…

DDD解决了什么问题

前言 前面我们有文章介绍了架构设计的目标以及DDD相关的领域知识&#xff0c;本章重点会介绍DDD到底在架构设计中解决了什么问题。 1. 系统复杂性的6个来源以及通用解法 架构设计的目标是管理系统复杂性以及高效率匹配资源。那系统复杂性源于好处呢&#xff1f; 1.1 高性能…