前言 : 在生活中我们经常会遇到通讯录的使用,比如存进一个新的联系人的信息,或者对其删除,修改,查找;那这些神奇的功能是如何实现的?我们不禁好奇。今天,这篇博文将教会大家实现一个静态的或者动态的通讯录,以后我们就可以靠自己实现一个通讯录啦 ~
目录一览
1.静态通讯录讲解1.1 静态通讯录的功能列表的实现(text.c)1.1.1 菜单的实现1.1.2 菜单功能的枚举1.1.3 main函数的实现1.2 静态通讯录各个函数的声明包含 (contact.h)1.2.1 #define 定义各个标号以及头文件的引用1.2.2 定义联系人信息结构体1.2.3定义静态通讯录结构体1.2.4 各个功能函数的声明1.3 功能函数的实现讲解 (contact.c)1.3.1 静态通讯录初始化函数讲解1.3.2 Add新增联系人函数的实现讲解1.3.3 展示当前存入的联系人信息函数讲解1.3.4 通过姓名查找当前存放进去的联系人信息位置函数实现讲解1.3.5 删除指定联系人函数实现讲解1.3.6 查找指定联系人函数实现讲解1.3.7 修改指定联系人信息函数实现讲解2.动态通讯录实现讲解2.1 动态通讯录结构体实现2.2 初始化动态通讯录函数讲解2.3 动态通讯录新增联系人函数实现讲解2.4 退出(销毁动态开辟的内存空间)通讯录函数实现讲解3.整体工程源代码展示3.1 text.c3.2 contact .c3.3 contact.h4.补充 :用文件方式实现退出通讯录可以保存信息的版本5.尾声1.静态通讯录讲解
1.1 静态通讯录的功能列表的实现(text.c)
1.1.1 菜单的实现
这里我们实现一个简易的功能菜单,运用print语句即可
功能有 1.新增联系人 2.删除联系人 3.查找指定联系人
4.修改指定联系人信息 5.展示目前存入的联系人 6.对联系人按照一定的标准排序 以及 0.退出通讯录
void menu(){printf("*******************************\n");printf("**** 1.add 2.del *****\n");printf("**** 3.search 4.modify *****\n");printf("**** 5.show6.sort *****\n");printf("**** 0.exit*****\n");printf("*******************************\n");}
1.1.2 菜单功能的枚举
enum Option{EXIT,ADD,DEL,SEARCH,MODIFY,SHOW,SORT};
EXIT 从0开始向下递增,分别对应菜单上的各个功能,目的是为了下面的switch接口能更加方便直观看出各个功能,以防出错。
1.1.3 main函数的实现
这一块我们实现从键盘上输入各个数字代表不同功能,再实现循环输入,
代码如下:
int main(){int input = 0;struct 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 SHOW:ShowContact(&con);break;case EXIT://销毁通讯录DestroyContact(&con);printf("退出通讯录\n");break;default:printf("选择错误\n");break;}} while (input);return 0;}
1.2 静态通讯录各个函数的声明包含 (contact.h)
1.2.1 #define 定义各个标号以及头文件的引用
#define DEFAULT_SZ 3#define NAME_MAX 30#define SEX_MAX 5#define TELE_MAX 12#define ADDR_MAX 30#define MAX 1000
分别定义了
默认存放联系人数量为3 (后面动态通讯录会使用到)
名字数组最大长度为 30‘
性别数组最大长度为 5
电话数组最大长度为 15
地址数组最大长度为 30
静态通讯录能存放最大联系人为 1000
头文件的引用:
#include <stdio.h>#include <string.h>#include <stdlib.h>#include <stdlib.h>
引用整个工程所要使用到的函数头文件,避免重复引用(每个文件前面加上 #include "contact.h),这样就实现所有声明头文件放在一个头文件中,分开管理,提升工程书写效率;
1.2.2 定义联系人信息结构体
struct PeoInfo{char name[NAME_MAX];int age;char sex[SEX_MAX];char tele[TELE_MAX];char addr[ADDR_MAX];};
1.2.3定义静态通讯录结构体
// 静态通讯录版本struct Contact{struct PeoInfo date[MAX];int sz;};
包含了可以存放1000个人信息的联系人结构体以及当前存放进去的有效联系人个数 sz ;
1.2.4 各个功能函数的声明
// 初始化通讯录 void InitContact(struct Contact* pc);//增加人的信息void Addcontact(struct Contact* pc);//显示联系人void ShowContact(struct Contact*pc);//删除指定联系人void DelContact(struct Contact* pc);//查找指定联系人void SearchContact(struct Contact* pc);//修改指定联系人void ModifyContact(struct Contact* pc);//销毁通讯录void DestroyContact(struct Contact* pc);
1.3 功能函数的实现讲解 (contact.c)
1.3.1 静态通讯录初始化函数讲解
// 静态直接开辟存放1000个人信息的版本void InitContact(struct Contact* pc){pc->sz = 0; //默认没有信息memset(pc->date, 0, MAX * sizeof(struct PeoInfo));//memset(pc->date, 0, sizeof(pc->date));}
结构体传参,传的一般是结构体地址,结构体指针接受,实现对结构体本身的修改 。(传址调用)
初始化有效联系人个数sz为0;
用memset内存设置函数,将1000个联系人信息结构体初始化为0;
1.3.2 Add新增联系人函数的实现讲解
// 静态版本void Addcontact(struct Contact* pc){struct Contact tmp = {0 };if (pc->sz == MAX){printf("通讯录可用空间已满\n");}else{printf("请输入名字:>");scanf("%s", pc->date[pc->sz].name);printf("请输入年龄:>");scanf("%d", &(pc->date[pc->sz].age));printf("请输入性别:>");scanf("%s", pc->date[pc->sz].sex);printf("请输入电话:>");scanf("%s", pc->date[pc->sz].tele);printf("请输入地址:>");scanf("%s", pc->date[pc->sz].addr);printf("添加成功\n");pc->sz++;}}
用pc->date[pc->sz].xxx找到各个联系人信息位置,将信息存入
后有效联系人个数sz++;
实现对下一个联系人信息的存放
1.3.3 展示当前存入的联系人信息函数讲解
void ShowContact(struct Contact* pc){int i = 0;printf("%15s\t%5s\t%8s\t%15s\t%30s\n","name", "age", "sex", "tele", "addr");for (i = 0; i < pc->sz; i++){//打印每一个数据printf("%15s\t%5d\t%8s\t%15s\t%30s\n",pc->date[i].name,pc->date[i].age,pc->date[i].sex,pc->date[i].tele,pc->date[i].addr);}}
printf("%15s\t%5s\t%8s\t%15s\t%30s\n",
“name”, “age”, “sex”, “tele”, “addr”);
实现初始化联系人信息表头的域宽
接下来打印每一个数据即可;
1.3.4 通过姓名查找当前存放进去的联系人信息位置函数实现讲解
int FindContactByName(const struct Contact* pc, const char* name){int i = 0;for (i = 0; i < pc->sz; i++){if (strcmp(pc->date[i].name, name) == 0){return i;}}return -1;}
strcmp库函数实现对字符串的比较,相同的话返回数字0;
返回数字0即代表查找成功,此时返回位置 i 即可;
查找不成功返回-1;
1.3.5 删除指定联系人函数实现讲解
void DelContact(struct Contact* pc){if (pc->sz == 0) //有效联系人个数为0{printf("通讯录为空,无法删除\n");return;}char name[NAME_MAX] = {0};printf("请输入要删除人的名字:>");scanf("%s", name);// 查找int pos=FindContactByName(pc, name);if (pos == -1){printf("指定的联系人不存在\n");}else{// 删除//将数组中要被删除的元素后面的元素相应向前放int j = 0;for (j = pos; j<pc->sz-1; j++){pc->date[j] = pc->date[j + 1];}pc->sz--;printf("删除成功\n");}}
相应讲解在代码中以注释形式给出;
1.3.6 查找指定联系人函数实现讲解
void SearchContact(const struct Contact* pc){char name[NAME_MAX] = {0 };printf("请输入要查找的联系人的名字:>");scanf("%s", name);int pos = FindContactByName(pc, name);if (pos == -1){printf("查无此人\n");}else{printf("%15s\t%5s\t%8s\t%15s\t%30s\n","name", "age", "sex", "tele", "addr");printf("%15s\t%5d\t%8s\t%15s\t%30s\n",pc->date[pos].name,pc->date[pos].age,pc->date[pos].sex,pc->date[pos].tele,pc->date[pos].addr);}}
查找成功的话将此位置(pos)打印出即可,格式和增加联系人函数的类似;
1.3.7 修改指定联系人信息函数实现讲解
void ModifyContact(struct Contact* pc){char name[NAME_MAX] = {0 };printf("请输入要修改的联系人的名字:>");scanf("%s", name);int pos = FindContactByName(pc, name);if (pos == -1){printf("要修改的联系人不存在\n");}else{printf("请输入新的名字:>");scanf("%s", pc->date[pos].name);printf("请输入新的年龄:>");scanf("%d", &(pc->date[pos].age));printf("请输入新的性别:>");scanf("%s", pc->date[pos].sex);printf("请输入新的电话:>");scanf("%s", pc->date[pos].tele);printf("请输入新的地址:>");scanf("%s", pc->date[pos].addr);printf("修改成功\n");}}
查找指定联系人成功的话,将此位置(pos)对应的联系人信息修改即可,
格式依旧和新增联系人函数类似;
到此为止,静态通讯录各个模块实现讲解基本完毕;
我们大致可以看一下效果 ;
2.动态通讯录实现讲解
动态通讯录与静态通讯录实现上大致相同,我们就把不同的地方区分出来进行详细讲解 :
动态通讯录与静态通讯录区别就在于: 静态通讯录一开始就创建好一个可以存放1000个人信息的空间,存不满的话对内存浪费就会比较大;
而动态通讯录可以实现随着放入的联系人信息的增多而相应的增加内存空间,用malloc函数实现,这样对内存空间的浪费就避免了,是更好的实现方法,下面我们就对动态通讯录进行讲解 :
2.1 动态通讯录结构体实现
//动态通讯录版本struct Contact{struct PeoInfo* date;int sz;int capacity;};
实现一个 date结构体指针,指向联系人信息结构体
实现一个当前有效联系人信息个数 sz
实现一个当前通讯录最大联系人容量 capacity
2.2 初始化动态通讯录函数讲解
// 动态开辟的版本void InitContact(struct Contact* pc){pc->sz = 0;pc->date = malloc(DEFAULT_SZ * sizeof(struct PeoInfo));pc->capacity = DEFAULT_SZ; // 3}
有效联系人个数sz制为0;
pc->date = malloc(DEFAULT_SZ * sizeof(struct PeoInfo));
malloc函数实现一开始动态内存开辟3个联系人空间大小,写法上
DEFAULT_SZ (元素个数:3)* sizeof(struct PeoInfo)(每个元素的大小)
返回开辟空间的地址,date结构体指针来接收;
一开始最大容量capacity制为 3 ;
2.3 动态通讯录新增联系人函数实现讲解
动态通讯录与静态通讯录不同就在新增联系人函数实现方式上有所变化,
其他函数一致保持不变 ;
// 动态版本void Addcontact(struct Contact* pc){// 空间满了就扩容if (pc->sz == pc->capacity){struct PeoInfo* ptr=(struct PeoInfo*)realloc(pc->date, (pc->capacity + 2) * sizeof(struct PeoInfo));if (ptr != NULL) // 扩容成功的话 {pc->date = ptr; // 扩容出来的新地址 ptr 赋给 date pc->capacity += 2; // 相应最大容量 +2 printf("扩容成功\n");}else{return; // 返回空指针 null 则 return }}// 录入新增人的信息// 实现上和静态通讯录无异printf("请输入名字:>");scanf("%s", pc->date[pc->sz].name);printf("请输入年龄:>");scanf("%d", &(pc->date[pc->sz].age));printf("请输入性别:>");scanf("%s", pc->date[pc->sz].sex);printf("请输入电话:>");scanf("%s", pc->date[pc->sz].tele);printf("请输入地址:>");scanf("%s", pc->date[pc->sz].addr);printf("添加成功\n");pc->sz++;}
struct PeoInfo* ptr=(struct PeoInfo*)realloc(pc->date, (pc->capacity + 2) * sizeof(struct PeoInfo));
扩容代码讲解:如果空间满了就用realloc函数实现扩容,realloc函数的意思是扩容为xx,不是扩容xx ;
realloc函数传入需要扩容的地址dete,扩容一次扩容+2个联系人空间,pc->capacity + 2,每个联系人大小为 sizeof(struct PeoInfo) ;
返回的地址强制类型转换为 (struct PeoInfo*)
存放在结构体指针 ptr 中 ;
其他讲解在代码中以注释形式给出 ;
2.4 退出(销毁动态开辟的内存空间)通讯录函数实现讲解
void DestroyContact(struct Contact* pc){free(pc->date);pc->date = NULL;pc->sz = 0;pc->capacity = 0;}
释放+制空:
free(pc->date);
pc->date = NULL;
实现避免对内存空间的浪费使用 ;
pc->sz = 0;
pc->capacity = 0;
将有效联系人个数以及最大联系人个数制为 0 ;
退出通讯录 ;
3.整体工程源代码展示
3.1 text.c
#define _CRT_SECURE_NO_WARNINGS 1#include "contact.h"void menu(){printf("*******************************\n");printf("**** 1.add 2.del *****\n");printf("**** 3.search 4.modify *****\n");printf("**** 5.show6.sort *****\n");printf("**** 0.exit*****\n");printf("*******************************\n");}enum Option{EXIT,ADD,DEL,SEARCH,MODIFY,SHOW,SORT};int main(){int input = 0;struct 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 SHOW:ShowContact(&con);break;case EXIT://销毁通讯录DestroyContact(&con);printf("退出通讯录\n");break;default:printf("选择错误\n");break;}} while (input);return 0;}
3.2 contact .c
#define _CRT_SECURE_NO_WARNINGS 1#include "contact.h" 静态直接开辟存放1000个人信息的版本 //void InitContact(struct Contact* pc)//{//pc->sz = 0; //默认没有信息//memset(pc->date, 0, MAX * sizeof(struct PeoInfo));////memset(pc->date, 0, sizeof(pc->date));//}//动态开辟的版本void InitContact(struct Contact* pc){pc->sz = 0;pc->date = malloc(DEFAULT_SZ * sizeof(struct PeoInfo));pc->capacity = DEFAULT_SZ; // 3}// 静态版本void Addcontact(struct Contact* pc){struct Contact tmp = {0 };if (pc->sz == MAX){printf("通讯录可用空间已满\n");}else{printf("请输入名字:>");scanf("%s", pc->date[pc->sz].name);printf("请输入年龄:>");scanf("%d", &(pc->date[pc->sz].age));printf("请输入性别:>");scanf("%s", pc->date[pc->sz].sex);printf("请输入电话:>");scanf("%s", pc->date[pc->sz].tele);printf("请输入地址:>");scanf("%s", pc->date[pc->sz].addr);printf("添加成功\n");pc->sz++;}}// 动态版本//void Addcontact(struct Contact* pc)//{// 空间满了就扩容//if (pc->sz == pc->capacity)//{//struct PeoInfo* ptr=(struct PeoInfo*)realloc(pc->date, (pc->capacity + 2) * sizeof(struct PeoInfo));//if (ptr != NULL)//{//pc->date = ptr;//pc->capacity += 2;//printf("扩容成功\n");//}//else//{//return;//}//}// 录入新增人的信息//printf("请输入名字:>");//scanf("%s", pc->date[pc->sz].name);//printf("请输入年龄:>");//scanf("%d", &(pc->date[pc->sz].age));//printf("请输入性别:>");//scanf("%s", pc->date[pc->sz].sex);//printf("请输入电话:>");//scanf("%s", pc->date[pc->sz].tele);//printf("请输入地址:>");//scanf("%s", pc->date[pc->sz].addr);//printf("添加成功\n");//pc->sz++;//}void ShowContact(struct Contact* pc){int i = 0;printf("%15s\t%5s\t%8s\t%15s\t%30s\n","name", "age", "sex", "tele", "addr");for (i = 0; i < pc->sz; i++){//打印每一个数据printf("%15s\t%5d\t%8s\t%15s\t%30s\n",pc->date[i].name,pc->date[i].age,pc->date[i].sex,pc->date[i].tele,pc->date[i].addr);}}int FindContactByName(const struct Contact* pc, const char* name){int i = 0;for (i = 0; i < pc->sz; i++){if (strcmp(pc->date[i].name, name) == 0){return i;}}return -1;}void DelContact(struct Contact* pc){if (pc->sz == 0){printf("通讯录为空,无法删除\n");return;}char name[NAME_MAX] = {0};printf("请输入要删除人的名字:>");scanf("%s", name);// 查找int pos=FindContactByName(pc, name);if (pos == -1){printf("指定的联系人不存在\n");}else{// 删除//将数组中要被删除的元素后面的元素相应向前放int j = 0;for (j = pos; j<pc->sz-1; j++){pc->date[j] = pc->date[j + 1];}pc->sz--;printf("删除成功\n");}}void SearchContact(const struct Contact* pc){char name[NAME_MAX] = {0 };printf("请输入要查找的联系人的名字:>");scanf("%s", name);int pos = FindContactByName(pc, name);if (pos == -1){printf("查无此人\n");}else{printf("%15s\t%5s\t%8s\t%15s\t%30s\n","name", "age", "sex", "tele", "addr");printf("%15s\t%5d\t%8s\t%15s\t%30s\n",pc->date[pos].name,pc->date[pos].age,pc->date[pos].sex,pc->date[pos].tele,pc->date[pos].addr);}}void ModifyContact(struct Contact* pc){char name[NAME_MAX] = {0 };printf("请输入要修改的联系人的名字:>");scanf("%s", name);int pos = FindContactByName(pc, name);if (pos == -1){printf("要修改的联系人不存在\n");}else{printf("请输入新的名字:>");scanf("%s", pc->date[pos].name);printf("请输入新的年龄:>");scanf("%d", &(pc->date[pos].age));printf("请输入新的性别:>");scanf("%s", pc->date[pos].sex);printf("请输入新的电话:>");scanf("%s", pc->date[pos].tele);printf("请输入新的地址:>");scanf("%s", pc->date[pos].addr);printf("修改成功\n");}}void DestroyContact(struct Contact* pc){free(pc->date);pc->date = NULL;pc->sz = 0;pc->capacity = 0;}
3.3 contact.h
#pragma once#define DEFAULT_SZ 3 #define NAME_MAX 30#define SEX_MAX 5#define TELE_MAX 12#define ADDR_MAX 30#define MAX 1000#include <stdio.h>#include <string.h>#include <stdlib.h>#include <stdlib.h>struct PeoInfo{char name[NAME_MAX];int age;char sex[SEX_MAX];char tele[TELE_MAX];char addr[ADDR_MAX];};// 静态通讯录版本//struct Contact//{//struct PeoInfo date[MAX];//int sz;//};//动态通讯录版本struct Contact{struct PeoInfo* date;int sz;int capacity;};// 初始化通讯录 void InitContact(struct Contact* pc);//增加人的信息void Addcontact(struct Contact* pc);//显示联系人void ShowContact(struct Contact*pc);//删除指定联系人void DelContact(struct Contact* pc);//查找指定联系人void SearchContact(struct Contact* pc);//修改指定联系人void ModifyContact(struct Contact* pc);//销毁通讯录void DestroyContact(struct Contact* pc);
4.补充 :用文件方式实现退出通讯录可以保存信息的版本
以上实现的无论是静态通讯录版本还是动态通讯录版本只要是退出了程序先前存的信息都会被销毁,那么我们怎么样才能做到退出保存信息,下次打开通讯录能加载上次退出时保存的信息呢?
答案就是 :用文件方式实现,退出了把信息存到文件中(.txt),打开时又加载上次保存的信息
这个版本实现改动并不复杂,只需要加上退出保存信息的函数以及打开加载信息的两个函数即可
改动展示如下: (相关解释在代码中以注释形式给出)
相关函数声明 :
退出时添加保存信息函数 :
保存信息函数 :
加载信息函数应放在初始化通讯录函数这里 :
加载信息函数 :
增容函数 CapaCity 展示 :
5.尾声
写到这里,关于静态通讯录和动态通讯录的讲解就已经完成,如果觉得文章对自己有所帮助,欢迎大家多多点赞收藏评论,这对博主来说是莫大的鼓励~谢谢各位啦 ~~
用C语言实现 静态通讯录+动态通讯录+文件实现“退出保存信息版本”(附上思路+项目展示+源代码)