C语言实现通讯录 (附完整代码)

C语言实现通讯录

  • 🍀实现一个通讯录:
  • 🍀通讯录的功能:
  • 🍀多文件实现
  • 💮设计结构体——保存人的信息
  • 💮初始通讯录
  • 💮封装通讯录
  • 💮define宏定义修改通讯录的最大容量
  • 初始化通讯录
  • 💐💐大致框架
  • 💐改进--枚举 提高代码的可读性
  • 🌼🌼定义函数实现功能
    • 🌼AddContact
    • 🌼ShowContact
    • 🌼DelContact
    • 🌼进一步改进
    • 🌼SearchContact
    • 🌼ModifyContact
    • 🌼Sort Contact
  • 🎆🎆🎆完整代码

🍀实现一个通讯录:

通讯录中保存人的信息:
名字
年龄
性别
电话
住址

🍀通讯录的功能:

1.通讯录可以存放100个人的信息
2.显示所有联系人的信息
3.排序功能
4.增:增加联系人
5.删:删除指定联系人
6.查:查找指定联系人
7.改:修改指定联系人

🍀多文件实现

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

💮设计结构体——保存人的信息

初级:

struct PeoInfo
{char name[20];int age;char sex[5];//一个汉字占两个字符char tele[12];char addr[30];
};

结构体的引用:

struct PeoInfo num1 ;
struct PeoInfo num2;
struct PeoInfo data[50];

改进:
考虑到每次使用结构体都需要写 struct PeoInfo比较繁琐,能不能直接把struct自己省略掉呢?
这时候就需要对改结构体进行重命名typedef

typedef struct PeoInfo
{char name[20];int age;char sex[5];char tele[12];char addr[30];
}PeoInfo;

这样,当我们使用结构体时,就不用用 struct PeoInfo了,直接使用PeoInfo就可以了。

💮初始通讯录

因为我们刚刚定义了结构体用来存储人的信息,但一个通讯录中有很多人,我们上面设置了该通讯录可以存放100个人的信息,所以我们需要用结构体数组将每一个类型都是结构体的元素存储起来。
C语言定义结构体数组一般形式:

结构体类型 数组名[数组长度];

所以我们定义 通讯录:

PeoInfo data[100];

同时,我们需要一个变量,来判断通讯录里已经存放数据的个数。(以防止在增添联系人时,超过了定义的通讯录的最大容量)

int sz=0;

💮封装通讯录

在上面考虑到通讯录PeoInfo data[100]和变量 sz是一种封锁的关系。即,sz等于几,PeoInfo data里面就有几个数据元素。sz加1,则PeoInfo data数组里会再存放一个元素。
所以,我们考虑将通讯录进行进一步的封装,构建一个结构体

typedef struct Contact
{PeoInfo data[100];int sz;
}Contact;

这时,我们的通讯录就为 con

Contact con;

💮define宏定义修改通讯录的最大容量


在这里插入图片描述
同样我们也可以对 我们刚开始定义的 姓名、地址、联系方式等 以同样的宏定义进行转变。

初始化通讯录

将通讯录初始化为0。可以定义一个函数,用来初始化通讯录。

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

因为我们要改变通讯录的内部,所以函数参数是一个地址值,类型是我们定义的通讯录结构体 Contact类型。
利用memset函数,将结构体中数组所有元素全部赋值为0.同时将pc所指向的sz也初始化为0.

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

💐💐大致框架

接下来,我们在void test ()函数中写一下大概的框架:
(因为要尽可能避免在主函数中太过冗长,所以我们把通讯录的具体实现——增删查找等等都放在test函数中,之后我们就只需要在主函数中进行调用即可。)

首先,我们可以用do...while循环 打印一个菜单。
定义一个函数 void menu()完成打印。在()函数中调用即可。
之后我们利用switch,对输入的input进行判断,进行相应的操作。对于下面的七种情况,我们可以写七个函数分别实现其相应的功能。

在这里插入图片描述
我们进行的所有操作都是对于通讯录而言的,所以在test函数中必须有通讯录。所以我们将我们已经初始化的通讯录放在函数中。
在这里插入图片描述
不要忘了包含头文件contact.h
(在contact.h头文件中,包含着本身已经封装好的常见的头文件 比如 <stdio.h><string.h>等,还有我们自己对于结构体或者函数的一些声明和定义,比如定义人的信息的结构体 PeoInfo、定义通讯录的 Contact,以及我们函数的声明,完成Contact初始化的函数InitContact等,还有之后,我们要对通讯录进行操作的一系列增删查找函数等函数的声明都会放在都文件中。)
(要注意,函数的定义不是放在头文件中的,而是在contat.c中)

在这里插入图片描述

💐改进–枚举 提高代码的可读性

在这里插入图片描述
在这里插入图片描述

🌼🌼定义函数实现功能

🌼AddContact

在这里插入图片描述

//增加联系人的信息
void AddContact(Contact* pc)
{//判断数组是否可以增添?if (pc->sz == 100){printf("通讯录已满,无法添加\n");return;}//通讯录没满else{printf("请输入名字:>");scanf("%s", pc->data[pc->sz].name);//pc->data 指向的是结构体数组 数组名本身就是地址,不用用取地址符号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("增加联系人成功!");}
}

🌼ShowContact

//显示所有联系人的信息
void ShowContact(const Contact* pc)//仅仅是显示,而不修改 所以用const限制修饰
{int i;for (i = 0; i < pc->sz; i++){printf("姓名:%-20s\t", pc->data[i].name);//根据联系人结构体信息printf("年龄:%-4d\t", pc->data[i].age);printf("性别:%-5s\t", pc->data[i].sex);printf("电话:%-12s\t", pc->data[i].tele);printf("住址:%-13s\t", pc->data[i].addr);//统一左对齐printf("\n");}
}


但是,当显示的数据变多的时候,尽管是左对齐,还是不够美观。
接下来,我们采用打印标题的形式,更好的打印出数据。

//显示所有联系人的信息
void ShowContact(const Contact* pc)//仅仅是显示,而不修改 所以用const限制修饰
{int i;//打印列标题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\t\n",pc->data[i].name,pc->data[i].age,pc->data[i].sex,pc->data[i].tele,pc->data[i].addr);}
}

🌼DelContact

//删除指定联系人
void DelContact(Contact* pc)
{int i = 0;char name[20];int pos = 0;int flag = 0;//输入要删除的人删除printf("请输入要删除人的名字:>");scanf("%s", name);//将要删除的人的名字放入name中(name本就是一个地址值)//查找有没有这个人for (i = 0; i < pc->sz; i ++){if (strcmp(name, pc->data[i].name) == 0) //字符串比较函数{pos = i;//找到了,记下位置flag = 1;}	}if (flag == 0){printf("要删除的人不存在\n");return;}//进行删除for (i = pos; i <pc->sz-1; i++){pc->data[i] = pc->data[i + 1];}pc->sz--;printf("成功删除联系人!");
}

🌼进一步改进

当我们写后面的函数时,我们发现后面的查找函数 还是 修改函数 都需要像 删除函数一样 先在通讯录类进行查找。
为了更高效完成整个工程,提高效率,我们可以来写一个通过名字进行查找的函数FindByName
当我们写 删除 查找 修改函数时,首先可以直接调用这个函数。

int FindByName(Contact* pc, char name[])
{int flag = 0;int i = 0;int pos;for (i = 0; i < pc->sz; i++){if (strcmp(name, pc->data[i].name) == 0) //字符串比较函数{pos = i;//找到了,记下位置return pos;}}if (flag == 0){printf("要删除的人不存在\n");return -1;}}

DelContact函数改进为:

//删除指定联系人
void DelContact(Contact* pc)
{int i = 0;char name[20];int pos = 0;int flag = 0;//输入要删除的人删除printf("请输入要删除人的名字:>");scanf("%s", name);//将要删除的人的名字放入name中(name本就是一个地址值)//查找有没有这个人if ((FindByName(pc, name) == -1)){printf("找不到要删除的联系人");}elsepos = FindByName(pc, name); //记下位置//进行删除for (i = pos; i <pc->sz-1; i++){pc->data[i] = pc->data[i + 1];}pc->sz--;printf("成功删除联系人!");
}

🌼SearchContact

在这里插入图片描述

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

🌼ModifyContact

在这里插入图片描述


//修改指定联系人
void ModifyContact(Contact* pc)
{int pos = 0;char name[20] = { 0 };printf("请输入要查找人的名字:>");scanf("%s", name);//查找有没有要修改的联系人if (FindByName(pc, name) == -1)printf("没有找到要修改的联系人\n");else {printf("找到了要修改的联系人!\n");pos = FindByName(pc, name);//修改 (修改可以理解为再次录入一遍信息)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("成功修改联系人!");}
}

🌼Sort Contact

//按照名字进行排序
//排序int cmp_name(const void* p1, const void* p2)
{return strcmp(((PeoInfo*)p1)->name, ((PeoInfo*)p2)->name);
}
void SortContact(Contact* pc)
{int i = 0;//利用qsort 函数qsort(pc->data, pc->sz, sizeof((pc->data)[0]), cmp_name);//打印列标题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\t\n",pc->data[i].name,pc->data[i].age,pc->data[i].sex,pc->data[i].tele,pc->data[i].addr);}}

🎆🎆🎆完整代码

contact.h

#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include <string.h>
#define MAX 100//声明结构体--保存人的信息
typedef struct PeoInfo
{char name[20];int age;char sex[5];//一个汉字占两个字符char tele[12];char addr[30];
}PeoInfo;
//声明结构体通讯录
typedef struct Contact
{PeoInfo data[MAX];int sz;
}Contact;
int FindByName(Contact* pc, char name[]);
void AddContact(Contact* pc);
void ShowContact(const Contact* pc);
void DelContact(Contact* pc);
void SearchContact( Contact* pc);
void SearchContact(Contact* pc);
void SortContact(Contact* pc);enum OPTION
{EXIT,//0ADD,//1DEL,//2SEARCH,//3MODIFY,//4SHOW,//5SORT//6
};//函数的声明--初始化通讯录
void InitContact(Contact* pc);

contact.c

#include "contact.h"void InitContact(Contact* pc)
{memset(pc->data, 0, sizeof(pc->data));pc->sz = 0;
}//增加联系人的信息
void AddContact(Contact* pc)
{//判断数组是否可以增添?if (pc->sz == 100){printf("通讯录已满,无法添加\n");return;}//通讯录没满else{printf("请输入名字:>");scanf("%s", pc->data[pc->sz].name);//pc->data 指向的是结构体数组 数组名本身就是地址,不用用取地址符号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("增加联系人成功!");}
}//显示所有联系人的信息
void ShowContact(const Contact* pc)//仅仅是显示,而不修改 所以用const限制修饰
{int i;//打印列标题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\t\n",pc->data[i].name,pc->data[i].age,pc->data[i].sex,pc->data[i].tele,pc->data[i].addr);}
}int FindByName(Contact* pc, char name[])
{int flag = 0;int i = 0;int pos;for (i = 0; i < pc->sz; i++){if (strcmp(name, pc->data[i].name) == 0) //字符串比较函数{pos = i;//找到了,记下位置return pos;}}if (flag == 0){printf("要删除的人不存在\n");return -1;}}//删除指定联系人
void DelContact(Contact* pc)
{int i = 0;char name[20];int pos = 0;int flag = 0;//输入要删除的人删除printf("请输入要删除人的名字:>");scanf("%s", name);//将要删除的人的名字放入name中(name本就是一个地址值)//查找有没有这个人if ((FindByName(pc, name) == -1)){printf("找不到要删除的联系人");}elsepos = FindByName(pc, name); //记下位置//进行删除for (i = pos; i <pc->sz-1; i++){pc->data[i] = pc->data[i + 1];}pc->sz--;printf("成功删除联系人!");
}//查找指定联系人
void SearchContact( Contact* pc)
{int pos = 0;char name[20] = { 0 };printf("请输入要查找人的名字:>");scanf("%s", name);//查找有没有指定联系人if (FindByName(pc, name) == -1)printf("没有找到要查找的联系人\n");else{pos = FindByName(pc, name);printf("找到了!\n");printf("该联系人的下标为%d", pos);//打印数据printf("%-20s\t%-4s\t%-5s\t%-12s\t%-30s\n", "名字", "年龄", "性别", "电话", "地址");printf("%-20s\t%-4d\t%-5s\t%-12s\t%-30s\t\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)
{int pos = 0;char name[20] = { 0 };printf("请输入要查找人的名字:>");scanf("%s", name);//查找有没有要修改的联系人if (FindByName(pc, name) == -1)printf("没有找到要修改的联系人\n");else {printf("找到了要修改的联系人!\n");pos = FindByName(pc, name);//修改 (修改可以理解为再次录入一遍信息)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("成功修改联系人!");}
}//按照名字进行排序
//排序int cmp_name(const void* p1, const void* p2)
{return strcmp(((PeoInfo*)p1)->name, ((PeoInfo*)p2)->name);
}
void SortContact(Contact* pc)
{int i = 0;//利用qsort 函数qsort(pc->data, pc->sz, sizeof((pc->data)[0]), cmp_name);//打印列标题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\t\n",pc->data[i].name,pc->data[i].age,pc->data[i].sex,pc->data[i].tele,pc->data[i].addr);}}

test.c


#include"contact.h"void menu()
{printf("\n");printf("******************\n");printf("******请选择******\n");printf("******1.增添******\n");printf("******2.删除******\n");printf("******3.查找******\n");printf("******4.修改******\n");printf("******5.显示******\n");printf("******6.排序******\n");printf("******0.退出******\n");}void test()
{Contact con;  //定义结构体变量-通讯录InitContact(&con);//对通讯录进行初始化int input = 0;do{menu();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.hqwc.cn/news/110408.html

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

相关文章

掌握这5种方法,让你的新AirPods充电盒更耐用!

每次AirPods充电盒落地时&#xff0c;你都会呼吸急促吗&#xff1f;无论我使用的是旧一代的AirPods还是最新的AirPod Pro 2&#xff0c;我都关心它们的保存状况&#xff0c;并尽力保护这些脆弱设备的安全。我想我对AirPods Pro 2的新充电盒也会有同样的感受&#xff0c;它在9月…

页面静态化、Freemarker入门

页面静态化介绍 页面的访问量比较大时&#xff0c;就会对数据库造成了很大的访问压力&#xff0c;并且数据库中的数据变化频率并不高。 那需要通过什么方法为数据库减压并提高系统运行性能呢&#xff1f;答案就是页面静态化。页面静态化其实就是将原来的动态网页(例如通过ajax…

千里共婵娟 | 结合微信公众号用JavaScript完整开发实现换中秋头像的功能

&#x1f3c6;作者简介&#xff0c;黑夜开发者&#xff0c;CSDN领军人物&#xff0c;全栈领域优质创作者✌&#xff0c;阿里云社区专家博主&#xff0c;2023年6月csdn上海赛道top4。 &#x1f3c6;数年电商行业从业经验&#xff0c;历任核心研发工程师&#xff0c;项目技术负责…

Jmeter 实现 mqtt 协议压力测试

1. 下载jmeter&#xff0c;解压 https://jmeter.apache.org/download_jmeter.cgi 以 5.4.3 为例&#xff0c;下载地址&#xff1a; https://dlcdn.apache.org//jmeter/binaries/apache-jmeter-5.4.3.zip linux下解压&#xff1a; unzip apache-jmeter-5.4.3.zip 2. 下载m…

【深度学习】- NLP系列文章之 1.文本表示以及mlp来处理分类问题

系列文章目录 1. 文本分类与词嵌入表示&#xff0c;mlp来处理分类问题 2. RNN、LSTM、GRU三种方式处理文本分类问题 3. 评论情绪分类 还是得开个坑&#xff0c;最近搞论文&#xff0c;使用lstm做的ssd的cache prefetching&#xff0c;意味着我不能再划水了。 文章目录 系列文章…

智能合约漏洞案例,DEI 漏洞复现

智能合约漏洞案例&#xff0c;DEI 漏洞复现 1. 漏洞简介 https://twitter.com/eugenioclrc/status/1654576296507088906 2. 相关地址或交易 https://explorer.phalcon.xyz/tx/arbitrum/0xb1141785b7b94eb37c39c37f0272744c6e79ca1517529fec3f4af59d4c3c37ef 攻击交易 3. …

深入理解右值引用与移动语义

文章目录 写在前面1. 什么是右值&#xff0c;什么是左值&#xff1f;1.1右值引用可以引用左值吗1.2 左值引用、右值引用本身是左值还是右值&#xff1f;1.3 特殊的 const 左值引用 2. 右值引用与移动构造的意义3. 移动构造函数的使用4. move的实现原理5. 完美转发 写在前面 本…

rust String 和 str 区别

1 String / &String String 类型的变量本质是一个存放在栈上的胖指针&#xff08;当然调用过程中&#xff0c;不用显示地按指针那样处理&#xff09;&#xff0c;共有三个字段&#xff1a; 1 pointer: 指向实际字符串值的地址&#xff0c;值是存放在堆上可变字节缓冲区&a…

焊接符号学习

欧美焊接符号举例 4.5------表示焊点直径 【3】------根据图示说明&#xff0c;表示此项为CC项或者SC项 6-------表示此处为第六CC项或者SC项 BETWEEN①AND②------表示①件和②件俩点之间的焊点 12X------表示俩点之间的焊点个数为12个 日本焊接符号举例 A------根据图示&…

JDK10特性

文章目录 JAVA10概述语法层次的变化局部变量的类型推断不能使用类型推断的场景变量的声明初始值nulllambda表达式方法引用为数组静态初始化成员变量不能使用其他不可以的场景 API层次的变化集合的copyOf方法 总结 JAVA10概述 2018年3月21日&#xff0c;Oracle官方宣布JAVA10正…

OSI模型与数据的封装

1、OSI模型 上层|| 七层模型 四层模型|| 应用层| 表示层 应用层 http/ftp/ssh/ftps| 会话层 -----------------------------------------------------------------------| 传输层 传输层 tcp/udp ------------------------------…

解决:Loading class `com.mysql.jdbc.Driver‘. This is deprecated.

1.在连接MySQL数据库时候会出现这个报错 Loading class com.mysql.jdbc.Driver. This is deprecated. The new driver class is com.mysql.cj.jdbc.Driver. The driver is automatically registered via the SPI and manual loading of the driver class is generally unneces…