初阶通讯录自主实现,就算你没学过C语言也没关系,手把手教你写出来,你还在等什么??
创始人
2024-05-10 22:09:29
0

目录

  • 一、通讯录简介
  • 二、结构体类型的定义
  • 三、test.c整体测试的框架
  • 四、Conatct.h
  • 五、通讯录各个函数的实现
    • 5.1 初始化通讯录函数的实现
    • 5.2 添加联系人函数的实现
    • 5.3 删除联系人函数的实现
    • 5.4 查找联系人函数的实现
    • 5.5 改变联系人信息函数的实现
    • 5.6 展示联系人信息函数的实现
    • 5.7 通讯录排序函数的实现
  • 六、通讯录完整代码汇总
  • 七、总结

一、通讯录简介

通讯录的实现分为三个模块:Contact.h Contact.c test.c
Contact.h:.h为后缀的文件一般放头文件的包含,结构体类型的定义,宏定义,函数的声明等等。
**Contact.c:**完成函数的实现。
**test.c:**测试通讯录功能。

二、结构体类型的定义

通讯录需要记录当前已经存放的联系人的个数以及由每一个联系人信息构成的数组,而对于任何一个联系人都是一个复杂的对象,需要用多个变量去描述这个联系人的特点,例如:需要姓名,性别,年龄等等,所以又需要一个结构体描述。,所以这里需要两个结构体嵌套使用。

#define MAX_CAPACITY 1000
//创建描述联系人信息的结构体
typedef struct peo_info
{char name[20];char sex[10];int age;char addr[20];char tele[12];
}peo_info;
//创建通讯录的结构体
typedef struct Contact
{//通讯录结构体里面嵌套一个保存联系人数据的结构体数组struct peo_info data[MAX_CAPACITY];int sz;}Contact;

三、test.c整体测试的框架

#include "contact.h"void menu(void)
{printf("*******************************\n");printf("****   1.add     2.del     ****\n");printf("****   3.search  4.mod     ****\n");printf("****   5.show    6.sort    ****\n");printf("*******     0.exit      *******\n");}int main()
{Contact con;//创建通讯录InitContact(&con);//初始化通讯录int input = 0;//对通讯录进行的操作do{menu();printf("请输入:>");scanf("%d", &input);switch (input){case 1:{Add(&con);//添加联系人break;}case 2:{Del(&con);//删除联系人break;}case 3:{Search(&con);//查找联系人break;}case 4:{Mod(&con);//修改联系人break;}case 5:{Show(&con);//展示联系人break;}case 6:{Sort(&con);//排序break;}case 0:{printf("退出通讯录!!!\n");break;}default:{printf("选择错误,请重新选择!!\n");break;}}} while (input);return 0;
}

四、Conatct.h

#include 
#include 
#include 
#include #define MAX_CAPACITY 1000
//创建描述联系人信息的结构体
typedef struct peo_info
{char name[20];char sex[10];int age;char addr[20];char tele[12];
}peo_info;
//创建通讯录的结构体
typedef struct Contact
{struct peo_info data[MAX_CAPACITY];int sz;}Contact;//函数声明
extern void InitContact(Contact* con);
extern void Add(Contact* con);
extern void Show(Contact* con);
extern void Del(Contact* con);
extern void Search(Contact* con);
extern void Mod(Contact* con);
extern void Sort(Contact* con);

五、通讯录各个函数的实现

5.1 初始化通讯录函数的实现

其实这里很简单,就是把存放联系人的数组初始化为0就行了,已经存放的联系人sz当然也为0

void InitContact(Contact* con)
{assert(con);memset(con->data, 0, sizeof(peo_info) * MAX_CAPACITY);con->sz = 0;
}

5.2 添加联系人函数的实现

void Add(Contact* con)
{assert(con);if (con->sz == MAX_CAPACITY){printf("通讯录已满,无法添加联系人!\n");return;}//con->data[con->sz].name的意思是通讯录con指向的data数组//下标为con->sz对应的peo_info结构体的name成员,由于每添加//一个数据con->sz就会++,所以下标刚好一一对应。printf("请输入添加的联系人姓名:>");scanf("%s", con->data[con->sz].name);printf("请输入添加的联系人性别:>");scanf("%s", con->data[con->sz].sex);	printf("请输入添加的联系人年龄:>");scanf("%d", &con->data[con->sz].age);printf("请输入添加的联系人电话:>");scanf("%s", con->data[con->sz].tele);printf("请输入添加的联系人地址:>");scanf("%s", con->data[con->sz].addr);con->sz++;printf("添加成功\n");
}

5.3 删除联系人函数的实现

int FindPeoInfo(Contact* con, char name[])
{assert(con);int i = 0;for (i = 0; i < con->sz; i++)//遍历查找{//返回值=0,证明通讯录里面下标为i的联系人的姓名与要查找的人的姓名//一样,证明找到了,返回i下标if (strcmp(con->data[i].name, name) == 0){return i;}}return -1;//循环遍历完都没有找到,那就是没有这个人了,返回-1代表找不到
}
void Del(Contact* con)
{assert(con);printf("请输入需要删除的联系人的名字:>");char name[20] = { 0 };scanf("%s", name);int pos = FindPeoInfo(con, name);//先查找指定联系人,再删除if (-1 == pos){printf("要删除的联系人不存在!\n");return;}int i = 0;for (i = pos; i < con->sz - 1; i++){//迭代往前挪,后一个数据覆盖前一个,最终把需要删除的位置覆盖掉con->data[i] = con->data[i + 1];}con->sz--;//删除一个元素con->sz自然也需要--。printf("删除成功!\n");
}

5.4 查找联系人函数的实现

int FindPeoInfo(Contact* con, char name[])
{assert(con);int i = 0;for (i = 0; i < con->sz; i++)//遍历查找{//返回值=0,证明通讯录里面下标为i的联系人的姓名与要查找的人的姓名//一样,证明找到了,返回i下标if (strcmp(con->data[i].name, name) == 0){return i;}}return -1;//循环遍历完都没有找到,那就是没有这个人了,返回-1代表找不到
}
void Search(Contact* con)
{assert(con);char name[20] = { 0 };printf("请输入需要查找的联系人的姓名:>");scanf("%s", name);int pos = FindPeoInfo(con,name);if (pos == -1){printf("找不到此联系人!\n");return;}//找到了就按照格式打印出来,‘\t’是制表符printf("%-20s\t%-10s\t%-5s\t%-12s\t%-20s\n", "姓名", "性别", "年龄", "电话", "地址");printf("%-20s\t%-10s\t%-5d\t%-12s\t%-20s\n", con->data[pos].name,con->data[pos].sex,con->data[pos].age,con->data[pos].tele,con->data[pos].addr);}

5.5 改变联系人信息函数的实现

int FindPeoInfo(Contact* con, char name[])
{assert(con);int i = 0;for (i = 0; i < con->sz; i++)//遍历查找{//返回值=0,证明通讯录里面下标为i的联系人的姓名与要查找的人的姓名//一样,证明找到了,返回i下标if (strcmp(con->data[i].name, name) == 0){return i;}}return -1;//循环遍历完都没有找到,那就是没有这个人了,返回-1代表找不到
}
void Mod(Contact* con)
{assert(con);printf("请输入需要修改的联系人的姓名:>");char name[20] = { 0 };scanf("%s", name);int pos = FindPeoInfo(con, name);if (pos == -1){printf("该联系人不存在!\n");return;}//下面其实就是跟添加联系人信息是一样的逻辑的//修改其实也是输入信息嘛printf("请输入新的联系人姓名:>");scanf("%s", con->data[pos].name);printf("请输入添加的联系人性别:>");scanf("%s", con->data[pos].sex);printf("请输入添加的联系人年龄:>");scanf("%d", &con->data[pos].age);printf("请输入添加的联系人电话:>");scanf("%s", con->data[pos].tele);printf("请输入添加的联系人地址:>");scanf("%s", con->data[pos].addr);printf("修改成功!\n");}

5.6 展示联系人信息函数的实现

void Show(Contact* con)
{assert(con);int i = 0;//先打印表头,可以更加美观printf("%-20s\t%-10s\t%-5s\t%-12s\t%-20s\n", "姓名", "性别", "年龄", "电话", "地址");//遍历格式化打印各个联系人信息就好咯for (i = 0; i < con->sz; i++){printf("%-20s\t%-10s\t%-5d\t%-12s\t%-20s\n", con->data[i].name,con->data[i].sex, con->data[i].age, con->data[i].tele, con->data[i].addr);}
}

5.7 通讯录排序函数的实现

这里大家可以用不同的方式对联系人进行排序,我这里就用qsort对联系人的名字进行的排序

int cmp_by_name(const void* e1, const void* e2)
{return strcmp(((peo_info*)e1)->name, ((peo_info*)e2)->name);
}void Sort(Contact* con)
{assert(con);qsort(con->data, con->sz, sizeof(con->data[0]), cmp_by_name);printf("排序成功\n");Show(con);}

另外一种写法是我自主实现一个通用的冒泡排序

void swap(char* buf1, char* buf2, size_t width)
{size_t i = 0;//数组中的每一个数据占width个字节,我们只需要循环width次就能把两个元素的每一个字节都交换,//最终两个元素的内容也就交换成功了for (i = 0; i < width; i++){char tmp = *buf1;*buf1 = *buf2;*buf2 = tmp;buf1++;buf2++;}}void bubble_sort(void* base, size_t sz, size_t width, int (*cmp)(const void* e1, const void* e2))
{//这里是典型的冒泡排序的方法size_t i = 0;for (i = 0; i < sz - 1; i++){size_t j = 0;for (j = 0; j < sz - 1 - i; j++){//这里的cmp函数就是就是比较相邻的两个元素的大小,如果返回值大于0,则证明前一个元素//比后一个元素大,则需要交换这两个元素。由于这里的base指针的类型是void*,所以我们//首先需要将它强制类型转换成char*类型的指针,那为什么是转换成char*而不是int*, //double*呢?其实很简单,你试想一下,我们比较完了两个相邻的元素之后是不是需要//拿后一个和这两个元素中大的元素进行比较大小,但是大家别忘了,指针类型的大小可是决 //定了你指针加1跳过几个字节的啊,整形指针加1跳过一个整形,字符指针加1跳过一个字节//但是我们并不知道将来这个函数会被用来排序什么类型的数据的啊,但是无论是数目类型的 //数据,它的大小都至少为1个字节吧,所以转换成(char*)类型是最合理的。而参数中的宽 //度又正好能让我们找到下一个元素,只需要再起始地址加上宽度*j就能找到下一个元素了//所以if语句里面的判断条件应该这样写if (cmp((char*)base + j * width, (char*)base + (j + 1) * width) > 0){swap((char*)base + j * width, (char*)base + (j + 1) * width, width);}}}}int cmp_by_name(const void* e1, const void* e2)
{//通过姓名对结构体进行排序,需要用到strcmp函数,依然是返回1,0,-1return strcmp(((peo_info*)e1)->name, ((peo_info*)e2)->name);
}void Sort(Contact* con)
{assert(con);//qsort(con->data, con->sz, sizeof(con->data[0]), cmp_by_name);bubble_sort(con->data, con->sz, sizeof(con->data[0]), cmp_by_name);printf("排序成功\n");Show(con);}

当然,这个排序的方法的性能肯定比不上qsort本来的性能的,所以这个只是作为一个通用的排序的方法的参考。

六、通讯录完整代码汇总

test.c

#define _CRT_SECURE_NO_WARNINGS 1#include "contact.h"void menu(void)
{printf("*******************************\n");printf("****   1.add     2.del     ****\n");printf("****   3.search  4.mod     ****\n");printf("****   5.show    6.sort    ****\n");printf("*******     0.exit      *******\n");}int main()
{Contact con;InitContact(&con);int input = 0;do{menu();printf("请输入:>");scanf("%d", &input);switch (input){case 1:{Add(&con);break;}case 2:{Del(&con);break;}case 3:{Search(&con);break;}case 4:{Mod(&con);break;}case 5:{Show(&con);break;}case 6:{Sort(&con);break;}case 0:{printf("退出通讯录!!!\n");break;}default:{printf("选择错误,请重新选择!!\n");break;}}} while (input);return 0;
}

contact.h

#pragma once#include 
#include 
#include 
#include #define MAX_CAPACITY 1000typedef struct peo_info
{char name[20];char sex[10];int age;char addr[20];char tele[12];
}peo_info;typedef struct Contact
{struct peo_info data[MAX_CAPACITY];int sz;}Contact;//函数声明
extern void InitContact(Contact* con);
extern void Add(Contact* con);
extern void Show(Contact* con);
extern void Del(Contact* con);
extern void Search(Contact* con);
extern void Mod(Contact* con);
extern void Sort(Contact* con);

contact.c

#define _CRT_SECURE_NO_WARNINGS 1#include "contact.h"void InitContact(Contact* con)
{assert(con);memset(con->data, 0, sizeof(peo_info) * MAX_CAPACITY);con->sz = 0;
}void Add(Contact* con)
{assert(con);if (con->sz == MAX_CAPACITY){printf("通讯录已满,无法添加联系人!\n");return;}printf("请输入添加的联系人姓名:>");scanf("%s", con->data[con->sz].name);printf("请输入添加的联系人性别:>");scanf("%s", con->data[con->sz].sex);	printf("请输入添加的联系人年龄:>");scanf("%d", &con->data[con->sz].age);printf("请输入添加的联系人电话:>");scanf("%s", con->data[con->sz].tele);printf("请输入添加的联系人地址:>");scanf("%s", con->data[con->sz].addr);con->sz++;printf("添加成功\n");
}void Show(Contact* con)
{assert(con);int i = 0;printf("%-20s\t%-10s\t%-5s\t%-12s\t%-20s\n", "姓名", "性别", "年龄", "电话", "地址");for (i = 0; i < con->sz; i++){printf("%-20s\t%-10s\t%-5d\t%-12s\t%-20s\n", con->data[i].name,con->data[i].sex, con->data[i].age, con->data[i].tele, con->data[i].addr);}
}int FindPeoInfo(Contact* con, char name[])
{assert(con);int i = 0;for (i = 0; i < con->sz; i++){if (strcmp(con->data[i].name, name) == 0){return i;}}return -1;
}void Del(Contact* con)
{assert(con);printf("请输入需要删除的联系人的名字:>");char name[20] = { 0 };scanf("%s", name);int pos = FindPeoInfo(con, name);if (-1 == pos){printf("要删除的联系人不存在!\n");return;}int i = 0;for (i = pos; i < con->sz - 1; i++){con->data[i] = con->data[i + 1];}con->sz--;printf("删除成功!\n");
}void Search(Contact* con)
{assert(con);char name[20] = { 0 };printf("请输入需要查找的联系人的姓名:>");scanf("%s", name);int pos = FindPeoInfo(con,name);if (pos == -1){printf("找不到此联系人!\n");return;}printf("%-20s\t%-10s\t%-5s\t%-12s\t%-20s\n", "姓名", "性别", "年龄", "电话", "地址");printf("%-20s\t%-10s\t%-5d\t%-12s\t%-20s\n", con->data[pos].name,con->data[pos].sex,con->data[pos].age,con->data[pos].tele,con->data[pos].addr);}void Mod(Contact* con)
{assert(con);printf("请输入需要修改的联系人的姓名:>");char name[20] = { 0 };scanf("%s", name);int pos = FindPeoInfo(con, name);if (pos == -1){printf("该联系人不存在!\n");return;}printf("请输入新的联系人姓名:>");scanf("%s", con->data[pos].name);printf("请输入添加的联系人性别:>");scanf("%s", con->data[pos].sex);printf("请输入添加的联系人年龄:>");scanf("%d", &con->data[pos].age);printf("请输入添加的联系人电话:>");scanf("%s", con->data[pos].tele);printf("请输入添加的联系人地址:>");scanf("%s", con->data[pos].addr);printf("修改成功!\n");}void swap(char* buf1, char* buf2, size_t width)
{size_t i = 0;//数组中的每一个数据占width个字节,我们只需要循环width次就能把两个元素的每一个字节都交换,//最终两个元素的内容也就交换成功了for (i = 0; i < width; i++){char tmp = *buf1;*buf1 = *buf2;*buf2 = tmp;buf1++;buf2++;}}void bubble_sort(void* base, size_t sz, size_t width, int (*cmp)(const void* e1, const void* e2))
{//这里是典型的冒泡排序的方法size_t i = 0;for (i = 0; i < sz - 1; i++){size_t j = 0;for (j = 0; j < sz - 1 - i; j++){//这里的cmp函数就是就是比较相邻的两个元素的大小,如果返回值大于0,则证明前一个元素//比后一个元素大,则需要交换这两个元素。由于这里的base指针的类型是void*,所以我们//首先需要将它强制类型转换成char*类型的指针,那为什么是转换成char*而不是int*, //double*呢?其实很简单,你试想一下,我们比较完了两个相邻的元素之后是不是需要//拿后一个和这两个元素中大的元素进行比较大小,但是大家别忘了,指针类型的大小可是决 //定了你指针加1跳过几个字节的啊,整形指针加1跳过一个整形,字符指针加1跳过一个字节//但是我们并不知道将来这个函数会被用来排序什么类型的数据的啊,但是无论是数目类型的 //数据,它的大小都至少为1个字节吧,所以转换成(char*)类型是最合理的。而参数中的宽 //度又正好能让我们找到下一个元素,只需要再起始地址加上宽度*j就能找到下一个元素了//所以if语句里面的判断条件应该这样写if (cmp((char*)base + j * width, (char*)base + (j + 1) * width) > 0){swap((char*)base + j * width, (char*)base + (j + 1) * width, width);}}}}int cmp_by_name(const void* e1, const void* e2)
{//通过姓名对结构体进行排序,需要用到strcmp函数,依然是返回1,0,-1return strcmp(((peo_info*)e1)->name, ((peo_info*)e2)->name);
}void Sort(Contact* con)
{assert(con);//qsort(con->data, con->sz, sizeof(con->data[0]), cmp_by_name);bubble_sort(con->data, con->sz, sizeof(con->data[0]), cmp_by_name);printf("排序成功\n");Show(con);}

七、总结

其实这个初阶的通讯录实现起来或许没有你想象的那么简单,但是也没有你想象的那么难,就是先把整个测试的架构建起来,然后就逐一实现每一个函数需要的功能就可以了,初阶的通讯录的分享就到这里,你学会了吗?后续将会出进阶的能够动态开辟空间的通讯录的实现,想看的记得点点关注哦!如果这篇文章对你有帮助,请动动你发财的小手点点赞呗!我们下期见。

相关内容

热门资讯

常用商务英语口语   商务英语是以适应职场生活的语言要求为目的,内容涉及到商务活动的方方面面。下面是小编收集的常用商务...
六年级上册英语第一单元练习题   一、根据要求写单词。  1.dry(反义词)__________________  2.writ...
复活节英文怎么说 复活节英文怎么说?复活节的英语翻译是什么?复活节:Easter;"Easter,anniversar...
2008年北京奥运会主题曲 2008年北京奥运会(第29届夏季奥林匹克运动会),2008年8月8日到2008年8月24日在中华人...
英语道歉信 英语道歉信15篇  在日常生活中,道歉信的使用频率越来越高,通过道歉信,我们可以更好地解释事情发生的...
六年级英语专题训练(连词成句... 六年级英语专题训练(连词成句30题)  1. have,playhouse,many,I,toy,i...
上班迟到情况说明英语   每个人都或多或少的迟到过那么几次,因为各种原因,可能生病,可能因为交通堵车,可能是因为天气冷,有...
小学英语教学论文 小学英语教学论文范文  引导语:英语教育一直都是每个家长所器重的,那么有关小学英语教学论文要怎么写呢...
英语口语学习必看的方法技巧 英语口语学习必看的方法技巧如何才能说流利的英语? 说外语时,我们主要应做到四件事:理解、回答、提问、...
四级英语作文选:Birth ... 四级英语作文范文选:Birth controlSince the Chinese Governmen...
金融专业英语面试自我介绍 金融专业英语面试自我介绍3篇  金融专业的学生面试时,面试官要求用英语做自我介绍该怎么说。下面是小编...
我的李老师走了四年级英语日记... 我的李老师走了四年级英语日记带翻译  我上了五个学期的小学却换了六任老师,李老师是带我们班最长的语文...
小学三年级英语日记带翻译捡玉... 小学三年级英语日记带翻译捡玉米  今天,我和妈妈去外婆家,外婆家有刚剥的`玉米棒上带有玉米籽,好大的...
七年级英语优秀教学设计 七年级英语优秀教学设计  作为一位兢兢业业的人民教师,常常要写一份优秀的教学设计,教学设计是把教学原...
我的英语老师作文 我的英语老师作文(通用21篇)  在日常生活或是工作学习中,大家都有写作文的经历,对作文很是熟悉吧,...
英语老师教学经验总结 英语老师教学经验总结(通用19篇)  总结是指社会团体、企业单位和个人对某一阶段的学习、工作或其完成...
初一英语暑假作业答案 初一英语暑假作业答案  英语练习一(基础训练)第一题1.D2.H3.E4.F5.I6.A7.J8.C...
大学生的英语演讲稿 大学生的英语演讲稿范文(精选10篇)  使用正确的写作思路书写演讲稿会更加事半功倍。在现实社会中,越...
VOA美国之音英语学习网址 VOA美国之音英语学习推荐网址 美国之音网站已经成为语言学习最重要的资源站点,在互联网上还有若干网站...
商务英语期末试卷 Part I Term Translation (20%)Section A: Translate ...