静态版通讯录的实现(详解)

news/2024/5/10 23:18:46/文章来源:https://blog.csdn.net/weixin_73142957/article/details/129692217

前言:内容包括三个模块:测试通讯录模块,声明模块,通讯录实现模块

实现一个通讯录:

1 可以存放100个人的信息

每个人的信息:

名字 性别 年龄 电话 地址

2 增加联系人信息

   删除联系人信息

   查找联系人信息

   修改联系人信息

   排序联系人信息

   打印联系人信息

由于删除,查找,修改都需要找到被操作联系人的下标,所以我们可以独立写一个FindByName函数,用于返回被操作联系人的下标,让删除,查找,修改函数直接调用FindByName函数

静态版的通讯录(固定的联系人个数)分三个文件实现:

main.c:测试通讯录

contact.c:通讯录的实现(函数功能的具体实现)

contact.h:声明+类型定义

结构体最好传地址,不要选择传值

传址效率高

效果:

 

整体实现:

main.c

#include"contact.h"
void menu()
{printf("*************************\n");printf("**** 1.add     2.del   **\n");printf("**** 3.search  4.modify**\n");printf("**** 5.sort    6.show  **\n");printf("**** 0.exit            **\n");
}enum Option
{EXIT,ADD,DEL,SEARCH,MODIFY,SORT,SHOW
};
int main()
{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 SORT:SortContact(&con);break;case SHOW:ShowContact(&con);break;case EXIT:printf("退出通讯录\n");break;default:printf("选择错误,请重新选择\n");break;}} while (input);return 0;
}

contact.h 

#pragma once
#include<stdio.h>
#include<string.h>
#include<stdlib.h>#define MAX 100
#define MAX_NAME 20
#define MAX_SEX 5
#define MAX_TELE 12
#define MAX_ADDR 20//表示一个人的信息
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 ShowContact(const Contact* pc);//增加联系人信息
void AddContact(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)
{pc->sz = 0;memset(pc->data, 0, sizeof(pc->data));
}void ShowContact(const Contact* pc)
{printf("%-10s %-5s %-5s %-12s %-20s\n", "姓名", "年龄", "性别", "电话", "地址");int i = 0;for (i = 0; i < pc->sz; i++){printf("%-10s %-5d %-5s %-12s %-20s\n", pc->data[i].name, pc->data[i].age, pc->data[i].sex, pc->data[i].tele, pc->data[i].addr);}
}void AddContact(Contact* pc)
{if (pc->sz == MAX){printf("通讯录已满\n");return;}printf("请输入姓名:");char name[MAX_NAME] = { 0 };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");
}static int FindByName(const Contact* pc, char name[])
{int i = 0;for (i = 0; i < pc->sz; i++){if (strcmp(pc->data[i].name, name) == 0){return i;}}return -1;
}void DelContact(Contact* pc)
{if (pc->sz == 0){printf("通讯录为空\n");return;}printf("请输入要删除人的名字:");char name[MAX_NAME] = { 0 };scanf("%s", name);int pos = FindByName(pc, name);if (pos == -1){printf("不存在要删除人的信息\n");return;}int i = 0;for (i = pos; i < pc->sz - 1; i++){pc->data[i] = pc->data[i + 1];}pc->sz--;printf("删除成功\n");
}void SearchContact(const Contact* pc)
{printf("请输入要查找人的名字:");char name[MAX_NAME] = { 0 };scanf("%s", name);int pos = FindByName(pc, name);if (pos == -1){printf("被查找人信息不存在\n");return;}printf("%-10s %-5s %-5s %-12s %-20s\n", "姓名", "年龄", "性别", "电话", "地址");printf("%-10s %-5d %-5s %-12s %-20s\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)
{printf("请输入被修改联系人的名字:");char name[MAX_NAME] = { 0 };scanf("%s", name);int pos = FindByName(pc, name);if (pos == -1){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].addr);printf("修改成功\n");
}int cmp_by_name(const void* e1, const void* e2)
{return strcmp(((PeoInfo*)e1)->name, ((PeoInfo*)e2)->name);
}
void SortContact(Contact* pc)
{qsort(pc->data, pc->sz, sizeof(PeoInfo), cmp_by_name);printf("排序成功\n");
}

模块1:测试通讯录 (main.c)

#include"contact.h"
void menu()
{printf("*************************\n");printf("**** 1.add     2.del   **\n");printf("**** 3.search  4.modify**\n");printf("**** 5.sort    6.show  **\n");printf("**** 0.exit            **\n");
}enum Option
{EXIT, //0ADD,  //1DEL,  //2SEARCH,//3MODIFY,//4SORT,  //5SHOW   //6
};
int main()
{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 SORT:SortContact(&con);break;case SHOW:ShowContact(&con);break;case EXIT:printf("退出通讯录\n");break;default:printf("选择错误,请重新选择\n");break;}} while (input);return 0;
}

思路:

1 do while循环上来先显示菜单让用户选择功能

2 switch语句根据用户的不同选择实现通讯录的增,删,查,改,排序,打印,退出

这里巧妙使用了enum枚举类型

enum里面的所有成员是未来的所有可能取值,值总0开始以1为增量递增

这样方便我们在设计case语句时可以直接使用功能的名字,而不需要记住每个功能的序号

模块2:声明+类型定义(contact.h)

#pragma once
#include<stdio.h>
#include<string.h>
#include<stdlib.h>#define MAX 100
#define MAX_NAME 20
#define MAX_SEX 5
#define MAX_TELE 12
#define MAX_ADDR 20//表示一个人的信息
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 ShowContact(const Contact* pc);//增加联系人信息
void AddContact(Contact* pc);//删除联系人信息
void DelContact(Contact* pc);//查找联系人信息
void SearchContact(const Contact* pc);//修改联系人信息
void ModifyContact(Contact* pc);//排序联系人信息
void SortContact(Contact* pc);

在这个模块里,我们定义类型和放置声明

1 需要存储一个人的姓名,年龄,性别,电话,地址作为联系人信息,使用结构体

   联系人信息的类型名重命名为PeoInfo

2 通讯录:多个联系人信息(使用数组)+联系人的个数

3 使用#define定义常量,方便以后调整数值,比如以前我要存100个联系人信息,现在我要存200个,那么可以直接将MAX 后面的100改成200,这样一个通讯录就能存下200人了

模块3:通讯录的实现(函数功能的具体实现)

初始化通讯录函数:InitContact

void InitContact(Contact* pc)
{pc->sz = 0;memset(pc->data, 0, sizeof(pc->data));
}

初始时联系人的个数sz为0,所有联系人的信息为0

使用memset函数初始化

memset头文件:

#include <string.h>

结构:

void * memset ( void * ptr, int value, size_t num )

第一个参数:要被初始化的元素的地址

第二个参数:初始化元素的个数

第三个参数:一个元素的大小,单位是字节

由于我们要将所有的联系人信息初始化为0,即将每个元素类型为PeoInfo的数组内容全部初始化为0,所以memset的使用如下:

memset(pc->data, 0, sizeof(pc->data))

pc->data:数组名表示数组首元素的地址

0:初始化的内容是0(元素要被初始化为什么)

sizeof(pc->data):数组的所有字节

sizeof(数组名):计算的是整个数组的大小,单位是字节

显示通讯录:void ShowContact

void ShowContact(const Contact* pc)
{printf("%-10s %-5s %-5s %-12s %-20s\n", "姓名", "年龄", "性别", "电话", "地址");//打印标题int i = 0;for (i = 0; i < pc->sz; i++){printf("%-10s %-5d %-5s %-12s %-20s\n", pc->data[i].name, pc->data[i].age, pc->data[i].sex, pc->data[i].tele, pc->data[i].addr);}
}

pc是指向通讯录类型的结构体的指针,此函数只负责打印通讯录中的所有信息,不会更改通讯录中的内容,所以使用const修饰*pc,保护*pc不会被修改

 %-20s:占多少宽度可以自己控制,加上负号,表示左对齐

pc->data[i].addr:pc是指向通讯录的指针,pc->data[i]:找到了通讯录中的成员data数组中的第i个元素,数组的每个元素类型是PeoInfo的结构体,使用.操作符就可以找到PeoInfo结构体中的成员:名字 性别 年龄 电话 地址

增加联系人信息:AddContact

void AddContact(Contact* pc)
{if (pc->sz == MAX){printf("通讯录已满\n");return;}printf("请输入姓名:");char name[MAX_NAME] = { 0 };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");
}

1 判断通讯录是否已满,满了则无法添加,直接返回

2 通讯录未满,添加联系人信息:

   sz记录了通讯录中联系人的个数,则添加一个联系人,它的下标是sz

   因为现有sz个联系人,则最后一个联系人的下标是sz-1,那么sz为下标的空间就是空的

3 添加成功后,sz++,表示联系人的个数+1了 

搜寻指定联系人并返回其下标:FindByName

static int FindByName(const Contact* pc, char name[])
{int i = 0;for (i = 0; i < pc->sz; i++){if (strcmp(pc->data[i].name, name) == 0){return i;}}return -1;
}

FindByName函数只服务于删除,查找,修改函数,static修饰FindByName函数,可以使得FindByName只能在自己的.c文件内部使用,即只能在contact.c文件内使用

1 遍历所有联系人信息,使用strcmp函数比较名字是否相同

2 若是strcmp的返回值为0,则表示相同,返回下标i

    若是整个循环结束后仍未返回有效下标,则说明找不到此人的信息,返回-1

    因为有效下标的值不可能为-1,所以返回-1可以表示找不到此人

删除联系人信息: DelContact

void DelContact(Contact* pc)
{if (pc->sz == 0){printf("通讯录为空\n");return;}printf("请输入要删除人的名字:");char name[MAX_NAME] = { 0 };scanf("%s", name);int pos = FindByName(pc, name);if (pos == -1){printf("不存在要删除人的信息\n");return;}int i = 0;for (i = pos; i < pc->sz - 1; i++){pc->data[i] = pc->data[i + 1];}pc->sz--;printf("删除成功\n");
}

   1 判断通讯录中联系人是否为空,为空则无需删除,直接返回

   2 不为空,则查找到要被删除联系人的下标,使用覆盖法:

       用FindByName函数返回联系人的下标:

       返回值为-1:被删除联系人的信息不存在

       返回其他值:覆盖法,后面的往前移

       注意:下标只需要循环到倒数第二个位置就行了

for (i = pos; i < pc->sz - 1; i++)

                  假设有 1 2 3 4 5,元素个数sz=5,要删除3:

                  3的位置上覆盖4的值,4的位置上覆盖5的值,删除结束

                  最后一次覆盖的动作是4的位置上覆盖5的值,即我们最后只需要得到4的下标就行

                  5的下标:sz-1,4的下标:sz-2

3 删除成功,sz--,联系人个数减少了一个

 查找联系人信息:SearchContact

void SearchContact(const Contact* pc)
{printf("请输入要查找人的名字:");char name[MAX_NAME] = { 0 };scanf("%s", name);int pos = FindByName(pc, name);if (pos == -1){printf("被查找人信息不存在\n");return;}printf("%-10s %-5s %-5s %-12s %-20s\n", "姓名", "年龄", "性别", "电话", "地址");printf("%-10s %-5d %-5s %-12s %-20s\n", pc->data[pos].name,pc->data[pos].age,pc->data[pos].sex,pc->data[pos].tele, pc->data[pos].addr);
}

若是查找到了,直接打印此联系人的信息即可,此联系人的下标存储在pos中 

 修改联系人信息:ModifyContact

          

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

查找到了直接修改此联系人的信息即可,即对存放此联系人信息的空间重新输入信息

排序联系人信息:SortContact 

int cmp_by_name(const void* e1, const void* e2)
{return strcmp(((PeoInfo*)e1)->name, ((PeoInfo*)e2)->name);
}
void SortContact(Contact* pc)
{qsort(pc->data, pc->sz, sizeof(PeoInfo), cmp_by_name);printf("排序成功\n");
}

qsort函数可以排序任意类型的数据

头文件:

#include <stdlib.h> 

结构:

void qsort (void* base, size_t num, size_t size,int (*compar)(const void*,const void*))

第一个参数:被排序元素的地址

第二个参数:待排序元素的个数

第三个参数:一个待排序元素的大小,单位是字节

第四个参数:自己需要设计的比较函数的地址

比较两个元素的函数遵循以下设计原型:

	
int compar (const void* p1, const void* p2)

我们按照名字来排序,设计cmp_by_name函数:

int cmp_by_name(const void* e1, const void* e2)
{return strcmp(((PeoInfo*)e1)->name, ((PeoInfo*)e2)->name);
}

由于e1和e2指针的类型都是void*,而void*不可直接解引用,++,--操作

所以我们需要将e1和e2强制转成PeoInfo*的指针(比较的两个元素是PeoInfo类型)

但是强制转换又是临时的,故而用结构体指针去访问其成员时,需要将(PeoInfo*)e1整体用括号括起来,才能使用->去访问其成员

比较两个字符串需要使用strcmp函数

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

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

相关文章

windows无盘启动技术开发之传统BIOS(Legacy BIOS)引导程序开发之二

by fanxiushu 2023-03-21 转载或引用请注明原始作者&#xff0c;接上文&#xff0c;这篇文章其实主要就是讲述上文中 Int13HookEntry 这个C函数的实现过程&#xff0c;看起来就一个函数&#xff0c;可实现起来一点也不轻松。首先得准备编译环境&#xff0c;因为是16位程序&…

LeetCode岛屿问题通用解决模板

文章目录前言第一题&#xff1a;求岛屿的周长模板整理遍历方向确定边界重复遍历问题处理模板解第一题第二题&#xff1a;求岛屿数量第三题&#xff1a;岛屿的最大面积第四题&#xff1a;统计子岛屿第五题&#xff1a;统计封闭岛屿的数目第六题&#xff1a;最大人工岛总结前言 …

04.hadoopHDFS

win java访问hadoop //复制文件夹,配置环境变量//配置HADOOP_HOME为我们的路径 ,hadoop-3.3.0 ,记得JAVA_HOME不要带有空格,!!!默认java安装环境有空格C:\Program Files//要在cmd hadoop -fs 查看是否配置成功//%HADOOP_HOME%\bin到path//maven添加依赖hadoop3.1.0//创建目录Be…

常见的CMS后台getshell姿势总结

目录 WordPress dedecms aspcms 南方数据企业系统 phpmyadmin日志 pageadmin 无忧企业系统 WordPress 默认后台登录地址 /wp-login.php /wp-admin 登录后在外观的编辑里面找一个模板&#xff0c;我们在404模板 (404.php)里面写入一句话后门 可以蚁剑连接 上传一个压缩…

自定义类型的超详细讲解ᵎᵎ了解结构体和位段这一篇文章就够了ᵎ

目录 1.结构体的声明 1.1基础知识 1.2结构体的声明 1.3结构体的特殊声明 1.4结构体的自引用 1.5结构体变量的定义和初始化 1.6结构体内存对齐 那对齐这么浪费空间&#xff0c;为什么要对齐 1.7修改默认对齐数 1.8结构体传参 2.位段 2.1什么是位段 2.2位段的内存分配…

web前端框架——Vue的特性

目录 前言&#xff1a; 一.vue 二.特性 1.轻量级 2.数据绑定 3.指令 4.插件 三.比较Angular 、React 、Vue 框架之间的比较 1. Angular Angular的优点&#xff1a; 2. React React 的优点&#xff1a; 3.vue 3.Vue的优点&#xff1a; 前言&#xff1a; 本篇文章…

QT开发笔记(多媒体)

多媒体 多媒体&#xff08;Multimedia&#xff09;是多种媒体的综合&#xff0c;一般包括文本&#xff0c;声音和图像等多种媒体形式。 在计算机系统中&#xff0c;多媒体指组合两种或两种以上媒体的一种人机交互式信息交流和传播媒体。 使用的媒体包括文字、图片、照片、声音…

头歌c语言实训项目-函数(2)

(创作不易&#xff0c;感谢有你&#xff0c;你的支持&#xff0c;就是我前行的最大动力&#xff0c;如果看完对你有帮助&#xff0c;请留下您的足迹&#xff09; 目录 第1关&#xff1a;模拟投掷骰子游戏: 题目&#xff1a; 代码思路&#xff1a; 代码表示&#xff1a; 第…

20230322英语学习

Why Are So Many Gen Z-Ers Drawn to Old Digital Cameras? 老式数码相机&#xff1a;Z世代的复古潮流 The latest digital cameras boast ever-higher resolutions, better performance in low light, smart focusing and shake reduction – and they’re built right into …

牛客C/C++刷题笔记(五)

122、对于"int *pa[5]&#xff1b;"的描述中&#xff0c;&#xff08; &#xff09;是正确的。 123、以下叙述中正确的是&#xff08;&#xff09; C语言的源程序中对缩进没有要求,所以A选项错误。C语言中区分大小写,main函数不能写成Main或_main,所以B选项错误。一…

声声不息,新“声”报到

魅力声音大家庭总群&#xff08;10&#xff09;大玲&#xff0c;刚见到新来的四川孩儿——樱桃&#xff0c;真是太可爱了&#xff01;可不就是&#xff0c;这孩儿真是招人稀罕&#xff0c;我现在就把她拉到咱大群里“大玲” 邀请 “樱桃” 加入群聊所有人 咱们大家庭迎来了第一…

【字符串】刷题

P4173残缺的字符串心得&#xff1a;这道题&#xff0c;我觉得是不难的&#xff0c;代码逻辑很清晰&#xff0c;但是提交就是有问题最后发现两个问题&#xff1a;scanf输入字符后要用getchar() 吞回车 !!!!&#xff08;天坑用 scanf 输入时&#xff0c;不管输入什么&#xff0c;…

C语言小程序:通讯录(静态版)

哈喽各位老铁们&#xff0c;今天给大家带来一期通讯录的静态版本的实现&#xff0c;何为静态版本后面会做解释&#xff0c;话不多说&#xff0c;直接开始&#xff01;关于通讯录&#xff0c;其实也就是类似于我们手机上的通讯录一样&#xff0c;有着各种各样的功能&#xff0c;…

30天从零到1创业螺旋式

趁梦想还在&#xff0c;想去的地方&#xff0c;现在就去&#xff1b;想做的事情&#xff0c;现在就做。一开始立刻启动的你的项目&#xff0c;安排好时间计划&#xff0c;拆分微模块&#xff0c;每天花20分钟去完善产品&#xff0c;去改变世界。可以为自己的创意设置临时办公室…

RK3588平台开发系列讲解(显示篇)DP显示调试方法

平台内核版本安卓版本RK3588Linux 5.10Android 12文章目录 一、查看 connector 状态二、强制使能/禁⽤ DP三、DPCP 读写四、Type-C 接口 Debug五、查看 DP 寄存器六、查看 VOP 状态七、查看当前显示时钟八、调整 DRM log 等级沉淀、分享、成长,让自己和他人都能有所收获!😄…

【数据结构】链队列的C语言实现

队列 1.队列的概念 队列 和栈一样&#xff0c;是一个 特殊的线性表。 队列只允许在一端进行插入数据操作&#xff0c;在另一端进行删除数据操作的特殊线性表。进行 插入操作 的一端称为 队尾&#xff0c;进行 删除操作 的一端称为队头。 队列中的元素遵守 先进先出(First I…

【类的继承与派生的知识点】

文章目录类的继承与派生的知识点类的继承与派生&#xff1a;类成员的访问&#xff1a;类型兼容规则&#xff1a;一个公有派生类的对象在使用上可以被当成基类的对象&#xff0c;反之不行单继承与多继承派生类的构造与析构类成员的标识与访问类的继承与派生的实验结果类型兼容规…

Baumer工业相机堡盟相机如何使用Sharpening图像锐化功能( Sharpening图像锐化功能的优点和行业应用)(C++)

项目场景 Baumer工业相机堡盟相机是一种高性能、高质量的工业相机&#xff0c;可用于各种应用场景&#xff0c;如物体检测、计数和识别、运动分析和图像处理。 Baumer的万兆网相机拥有出色的图像处理性能&#xff0c;可以实时传输高分辨率图像。此外&#xff0c;该相机还具…

【计算机网络】如何解决TCP粘包问题?

【计算机网络】如何解决TCP粘包问题&#xff1f; 文章目录【计算机网络】如何解决TCP粘包问题&#xff1f;如何理解字节流&#xff1f;如何解决粘包&#xff1f;固定长度的消息特殊字符作为边界自定义消息结构如何理解字节流&#xff1f; 之所以会说 TCP 是面向字节流的协议&a…

RK3588编译环境Ubuntu20.04编译配置-增加交换内存

迅为提供的编译环境 Ubuntu20.04 默认配置了交换内存是 9G&#xff0c;如果在编译过程中&#xff0c;因内 存不够而编译报错&#xff0c;可以参考本小节进行设置。 这里举例分配 5G 交换内存。 在开始之前&#xff0c;使用命令检查一下您的 ubuntu 的 swap 分区。 sudo swa…