通讯录
用单链表实现通讯录需要五个文件
但其实三个文件也可以实现
test.c 测试通讯录函数
Contact.h 声明通讯录函数,定义结构体
Contact.c 实现通讯录函数
为了方便,就调用单链表的部分函数来实现通讯录
通讯录的结构
通讯录的结构体中要有:
姓名,性别,年龄,电话,地址
#pragma once
#define NAME_MAX 100 //姓名不超过100字节
#define SEX_MAX 20 //性别不超过20字节
#define TEL_MAX 11 //电话号码都是11位的
#define ADDR_MAX 100 //地址不超过100字节
//名字,性别,电话,地址都为char类型
//都设置最大存储大小
//前置声明
typedef struct SListNode contact;
//通讯录是基于单链表实现的,所以把链表的名字重命名为contact
//前置声明了这个单链表后续就可以使用了
//用户数据
typedef struct PersonInfo
{
char name[NAME_MAX];//姓名
char sex[SEX_MAX];//性别
int age;//年龄
char tel[TEL_MAX];//电话
char addr[ADDR_MAX];//地址
}PeoInfo;
//将通讯录重命名为PeoInfo
初始化通讯录
//初始化通讯录
//为头结点开辟空间
void InitContact(contact** con)
{
//直接调用单链表的初始化
SLInit(*con);
//初始化可以看我的上一篇博客
}
添加通讯录数据
//添加通讯录数据
void AddContact(contact** con)
{
PeoInfo info;
//定义一个通讯录结构体变量
printf("请输入联系人姓名\n");
scanf("%s", info.name);
printf("请输入联系人性别\n");
scanf("%s", info.sex);
printf("请输入联系人年龄\n");
scanf("%d", &info.age);
printf("请输入联系人电话\n");
scanf("%s", info.tel);
printf("请输入联系人地址\n");
scanf("%s", info.addr);
SLPushBack(con, info);
//尾插的实现也可以看我之前的博客
//用尾插把输入的数据插入到通讯录中
printf("插入成功\n");
}
查找联系人信息
//查找联系人信息
contact* FindByName(contact* con, char name[])
{
contact* pcur = con;
while (pcur)
{
if ((strcmp(pcur->data.name, name)) == 0)
// pcur->data.name 和 name 一样大就找到联系人的姓 名了
//strcmp要包含的头文件是 string.h
{
return pcur;
//返回存储联系人数据的节点
}
pcur = pcur->next;
//没有找到节点往下走,知道节点走到NULL,退出循环
}
return NULL;
//找不到name,返回空指针
}
删除联系人数据
//删除通讯录数据
void DelContact(contact** con)
// 传二级指针,为了改变指针的指向,改变一级指针的值
{
char name[NAME_MAX];
printf("请输入要删除的联系人姓名\n");
scanf("%s", name);
contact* pos = FindByName(*con, name);
//查找联系人姓名,找到返回联系人节点指针,找不到返回NULL
if (pos == NULL)
{
//找不到联系人姓名
printf("要删除联系人姓名不存在\n");
return;
//提前返回
}
//找到了联系人姓名
SLErase(con, pos);
//调用删除函数,删除pos节点
printf("删除成功\n");
}
展示通讯录信息
//展示通讯录数据
void ShowContact(contact* con)
//不改变指针的指向,用一级指针就可以找到节点中的数据
{
printf("姓名 性别 年龄 电话 地址\n");
contact* pcur = con;
while (pcur)
{
printf("%s %s %d %s %s\n",
pcur->data.name,
pcur->data.sex,
pcur->data.age,
pcur->data.tel,
pcur->data.addr);
//打印 姓名,性别,年龄,电话,地址
pcur = pcur->next;
//直到链表节点指针指向空,就打印完成
}
}
查找通讯录数据
//查找通讯录数据
void FindContact(contact* con)
{
char name[NAME_MAX];
printf("请输入要查找的联系人姓名\n");
scanf("%s", name);
contact* pos = FindByName(con, name);
//查找联系人姓名,找到返回联系人节点指针,找不到返回NULL
if (pos == NULL)
{
perror("FindByName");
return;
//提前返回
}
//要查找的联系人信息存在
printf("联系人数据存在\n");
//打印出来
printf("%s %s %d %s %s\n",
pos->data.name,
pos->data.sex,
pos->data.age,
pos->data.tel,
pos->data.addr);
}
修改通讯录数据
//修改通讯录数据
void ModifyContact(contact** con)
//用二级指针可以改变指针的指向(指针的值)
{
char name[NAME_MAX];
printf("请输入要修改的联系人姓名\n");
scanf("%s",name);
contact* pos = FindByName(*con, name);
//查找联系人姓名,找到返回联系人节点指针,找不到返回NULL
//找不到联系人信息
if (pos == NULL)
{
perror("FindByName");
return;
//提前返回
}
//找到了联系人信息
//修改联系人信息
//打印表头
//printf("姓名 性别 年龄 电话 地址\n");
printf("请输入改变后的联系人的姓名\n");
scanf("%s", pos->data.name);
printf("请输入改变后的联系人的性别\n");
scanf("%s", pos->data.sex);
printf("请输入改变后的联系人的年龄\n");
scanf("%d", &(pos->data.age));
printf("请输入改变后的联系人的电话\n");
scanf("%s", pos->data.tel);
printf("请输入改变后的联系人的地址\n");
scanf("%s", pos->data.addr);
}
销毁通讯录数据
传二级指针是为了改变指针的指向(指针的值),比如 * con = NULL,那么指向头结点的指针的值为NULL,传回主函数中con就是NULL,因为传址调用形参会改变实参的值,二级指针解引用,找到一级指针的内容,把一级指针的内容改变了,一级指针的内容是一个地址,一级指针通过本身被改变的地址内容,一级指针的指向就被改变了
而传一级指针,比如 con = NULL,这个函数结束后,传回主函数时,传值调用形参不会改变实参,所以到主函数里con并没有被置为NULL
//销毁通讯录数据
void DestroyContact(contact** con)
{
//直接调用SList.c中实现的销毁方法
SLDestroy(con);
//可以看我之前写的博客
}