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("找不到要删除的联系人");
}
else
pos = 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,//0
ADD,//1
DEL,//2
SEARCH,//3
MODIFY,//4
SHOW,//5
SORT//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("找不到要删除的联系人");
}
else
pos = 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;
}