初阶通讯录自主实现,就算你没学过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);}

七、总结

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

相关内容

热门资讯

幼儿园晨会主持词 幼儿园晨会主持词  美好的一天从早上开始,从晨会开始,从大家的好的状态开始,从最好的开始。以下是小编...
诗文诵读展示主持词 诗文诵读展示主持词  主持词没有固定的格式,他的最大特点就是富有个性。在当今不断发展的世界,很多晚会...
大学生毕业典礼的主持词 大学生毕业典礼的主持词(精选5篇)  活动对象的不同,主持词的写作风格也会大不一样。在当下的社会中,...
婚礼的主持词 婚礼的主持词  婚礼的主持词(精选21篇)  主持词的写作要突出活动的主旨并贯穿始终。随着社会一步步...
主婚人致辞 主婚人致辞(精选6篇)  在生活、工作和学习中,大家都写过致辞吧,致辞具有很强的实用性和针对性。还在...
促销活动主持词 促销活动主持词  利用在中国拥有几千年文化的诗词能够有效提高主持词的感染力。在现今人们越来越重视活动...
小品活动的主持词 小品活动的主持词  【篇一】  各位亲爱的老师,同学们,大家下午好!  欢迎来到天津师范大学新闻传播...
森林报好词好句 森林报好词好句  好词:  小巧玲珑 飞云流雾 红日西垂 霞光四射 层峦叠嶂 水天相接  轻歌曼舞 ...
早会主持稿 早会主持稿(精选5篇)  在现在社会,我们可以使用主持稿的机会越来越多,主持稿是主持人为节目进行过程...
优秀员工颁奖词 优秀员工颁奖词大全  在平时的学习、工作或生活中,大家都经常接触到颁奖词吧,颁奖词是在某一主题的颁奖...
女儿出阁司仪主持词 女儿出阁司仪主持词范文  主持词要把握好吸引观众、导入主题、创设情境等环节以吸引观众。在当下的中国社...
歌颂祖国串词 歌颂祖国串词一。各位领导 各位来宾,大家晚上好。今天我们这里篷壁生辉,喜气洋溢,是因为有您们的光临,...
小学生庆元旦联欢会主持词 小学生庆元旦联欢会主持词范文(精选5篇)  主持词要注意活动对象,针对活动对象写相应的主持词。在现今...
新年升旗仪式致辞 新年升旗仪式致辞(精选14篇)  在现实生活或工作学习中,说到致辞,大家肯定都不陌生吧,致辞具有思路...
表演半台词 表演三句半台词  敲锣打鼓走圆场  1:锣鼓一响好心情,  2:我们漫游动画城;  3:表演一个三句...
毕业30周年同学聚会主持词 毕业30周年同学聚会主持词范文  老同学聚会,一桌饭菜,谈论着当年的同学情,好不快活呀,往日是多么的...
结训典礼主持词 结训典礼主持词范文  主持词是主持人在节目进行过程中用于串联节目的串联词。在当今中国社会,各种集会中...
集团董事长新年的经典致辞 集团董事长新年的经典致辞(通用13篇)  在平平淡淡的学习、工作、生活中,大家对致辞都不陌生吧,致辞...