通讯录是在顺序表的基础上实现的。我们知道,顺序表可以存储各种数据类型,自定义类型也能够存储,结构体就是一个自定义类型的数据。
假设一条联系人数据 包括姓名、性别、年龄、电话、住址等信息,我们将这些信息封装到一个结构体里面,再将这个结构体插入到顺序表中,就构成了一个通讯录。
还不了解顺序表的朋友可以看我上一篇博客 动态顺序表的实现
首先呢,要先创建一个能存储一条联系人数据的结构体 struct personInfo,为了以后方便修改,用预定义符号让联系人的每一条信息成为定长。在Contact.h头文件中
#define NAME_MAX 20
#define GENDER_MAX 10
#define TEL_MAX 20
#define ADDR_MAX 100
//定义联系人数据结构
//姓名、性别、年龄、电话、住址
typedef struct personInfo
{
char name[NAME_MAX];
char gender[GENDER_MAX];
int age;
char tel[TEL_MAX];
char addr[ADDR_MAX];
}perinfo;
由于是在顺序表中插入联系人数据,所以在Seqlist.h头文件中也要包含Contact.h头文件。接下来就是对通讯录进行相关操作。
对通讯录的从操作实际上就是顺序表进行操作,因为通讯录中的联系人数据在顺序表中存储。那么我们索性就给顺序表改个名字,就让它叫通讯录,这样就是在通讯录中对联系人数据进行操作。
//冲定义顺序表,让它叫作通讯录
typedef struct Seqlist Contact;
当顺序表中的数据类型从int类型变为了结构体类型,就是说Seqlist.h头文件也要包含Contact.h头文件,才能用上结构体数据类型。但是这两者互相包含不是相互矛盾吗?所以就只在Contact.h头文件中包含Seqlist.h头文件,但是在Contact.h头文件中前置声明一下顺序表结构stract Seqlist。
什么是前置声明? 前置声明是在使用某个类之前,先声明该类的存在及其名称,但不提供该类的实现细节的一种语法结构。因为我们都给顺序表改了个名字叫作通讯录,也就是后续用不上stract Seqlist了,用的是typedef struct Seqlist Contact。
接下来就是对通讯录进行初始化 在Contact.c文件中
对通讯录进行初始化,实际上就是对顺序表进行初始化。但是顺序表的初始化是在Seqlist.h文件中,所以在Contact.c文件中要包含Seqlist.h头文件
通讯录的初始化实际上就是顺序表的初始化,通讯录的销毁实际上就是顺序表的销毁,因为通讯录就是顺序表。
通讯录添加数据:要创建一个结构体变量用于将添加的数据进行保存。
//通讯录添加数据
void ContactAdd(Contact* con)
{
//获取用户输入的内容:姓名、性别、年龄、电话、住址
perinfo info;//创建结构体变量
printf("请输入要添加的联系人姓名:\n");
scanf("%s", info.name);
printf("请输入要添加的联系人性别:\n");
scanf("%s", info.gender);
printf("请输入要添加的联系人年龄:\n");
scanf("%s", &info.age);
printf("请输入要添加的联系人电话:\n");
scanf("%s", info.tel);
printf("请输入要添加的联系人住址:\n");
scanf("%s", info.addr);
//往通讯录中添加联系人数据
//用顺序表中随便哪一种添加方式都行
InsertBack(con, info);//输入的信息都保存在了结构体变量info里面
}
删除联系人数据:首先要查找所要删除联系人存不存在,可以通过姓名、性别、年龄、电话、住址等内容查找用户。
//查找
int Find(Contact* con, char name[])
{
for (int i = 0; i < con->size; i++)//遍历次数
{
if (0 == strcmp(con->arr[i].name, name))
{
//找到了,返回下标,该下标所处位置就是要删除联系人的位置
return i;
}
}
//没有找到
return -1;
}
解释一下这里的con->arr[i].name,arr是一个结构体指针,更准确的来说是指向联系人数据的指针,arr[i].name是该一条联系人中的姓名信息 和 你要删除的联系人姓名用strcmp函数进行比较,两个姓名如果一样就返回0,就能得到该条联系人在通讯录中的下标。然后再通过下标进行删除。
//通讯录删除数据
void ContactDel(Contact* con)
{
//前提,要删除的数据必须要存在才能删除
//先进行查找 根据任意一种类型都行
char name[NAME_MAX];
printf("请输入要删除的联系人姓名:\n");
scanf("%s", name);
int find = Find(con, name);//con指传递通讯录
if (find < 0)
{
printf("要删除的联系人不存在!\n");
return;
}
//存在,删除对应下标
DeleteInsert(con, find);
printf("删除成功!\n");
}
修改联系人数据
要修改联系人数据,也要先查找联系人存不存在,也可以通过姓名、性别、年龄、电话、住址等内容查找用户。如果用户存在,对新的数据依次填写。
//通讯录的修改
void ContactModify(Contact* con)
{
{
//要修改的联系人数据存在
char name[NAME_MAX];
printf("请输入要修改的用户姓名:\n");
scanf("%s", name);
int find = Find(con, name);
if (find < 0)
{
printf("要修改的联系人数据不存在!\n");
return;
}
//直接修改
printf("请输入新的姓名:\n");
scanf("%s", con->arr[find].name);
printf("请输入新的性别:\n");
scanf("%s", con->arr[find].gender);
printf("请输入新的年龄:\n");
scanf("%d", &con->arr[find].age);
printf("请输入新的电话:\n");
scanf("%s", con->arr[find].tel);
printf("请输入新的住址:\n");
scanf("%s", con->arr[find].addr);
printf("修改成功!\n");
}
}
查找联系人
要先判断联系人存不存在,才能进行查找。
//通讯录的查找
void ContactFind(Contact* con)
{
//11
char name[NAME_MAX];
printf("请输入要查找的联系人姓名\n");
scanf("%s", name);
int find = Find(con, name);
if (find < 0)
{
printf("要查找的联系人数据不存在!\n");
return;
}
// 姓名 性别 年龄 电话 地址
// 11 11 11 11 11
printf("%s %s %s %s %s\n", "姓名", "性别", "年龄", "电话", "地址");
printf("%-4s %-4s %-4d %-4s %-4s\n", //手动调整一下格式
con->arr[find].name,
con->arr[find].gender,
con->arr[find].age,
con->arr[find].tel,
con->arr[find].addr
);
}
这里的con是一个结构体指针变量,指向结构体的成员。联系人的所有信息都存储在arr数组里面,如果联系人数据存在,Fund函数返回这个联系人的下标,最后将这个联系人的所有信息展示出来。
最后就是展示所有已经存储的联系人信息了
//通讯录的展示
void ContactShow(Contact* con)
{
printf("%s %s %s %s %s\n", "姓名", "性别", "年龄", "电话", "地址");
//遍历通讯录
for (int i = 0; i < con->size; i++)
{
printf("%-4s %-4s %-4d %-4s %-4s\n",
con->arr[i].name,
con->arr[i].gender,
con->arr[i].age,
con->arr[i].tel,
con->arr[i].addr
);
}
}
Seqlist.h和Seqlist.c文件没有很大的改动,是这个通讯录实现的基础,具体可以看我上一篇博客动态顺序表的实现
Contact.h文件
#pragma once
#define NAME_MAX 20
#define GENDER_MAX 10
#define TEL_MAX 20
#define ADDR_MAX 100
//前置声明
//struct Seqlist;
//定义联系人数据结构
//姓名、性别、年龄、电话、住址
typedef struct personInfo
{
char name[NAME_MAX];
char gender[GENDER_MAX];
int age;
char tel[TEL_MAX];
char addr[ADDR_MAX];
}perInfo;
//重定义顺序表,让它叫作通讯录
typedef struct Seqlist Contact;//不能用SL,因为不包含头文件
//通讯录的初始化
void ContactInit(Contact* con);
//通讯录的销毁
void ContactDestroy(Contact* con);
//通讯录添加数据
void ContactAdd(Contact* con);
//通讯录删除数据
void ContactDel(Contact* con);
//通讯录的修改
void ContactModify(Contact* con);
//通讯录的查找
void ContactFind(Contact* con);
//通讯录的展示
void ContactShow(Contact* con);
test.c文件(用来测试)
#define _CRT_SECURE_NO_WARNINGS 1
#include "Seqlist.h"
//void text()
//{
// SL s;
// Init(&s);
// 尾插数据
// InsertBack(&s, 1);
// InsertBack(&s, 2);
// InsertBack(&s, 3);
// InsertBack(&s, 4);
// 在指定位置之前插入数据
// SpecityInsert(&s, 2, 5);
// SpecityInsert(&s, 3, 6);
// Print(s);
// 在指点位置删除数据
// DeleteInsert(&s, 1);
// Print(s);//1 2 3 4
//
// destroy(&s);
//}
//通讯录的测试方法
void ContactTest01()
{
Contact con;//创建的通讯录对象,实际上是 SL s
ContactInit(&con);//初始化
ContactAdd(&con);
ContactAdd(&con);
ContactAdd(&con);
ContactShow(&con);
ContactDel(&con);
ContactShow(&con);
ContactModify(&con);
ContactShow(&con);
ContactFind(&con);
ContactDestroy(&con);//销毁
}
void menu()
{
Contact con;
ContactInit(&con);//初始化
int input;
do
{
printf("*******1、添加 2、删除*******\n");
printf("*******3、修改 4、查找*******\n");
printf("*******5、展示所有联系人*******\n");
printf("******* 0、退出 *******\n");
printf("请选择你的操作:");
scanf("%d", &input);
switch (input)
{
case 0:
printf("退出成功\n");
break;
case 1:
ContactAdd(&con);
printf("\n");
continue;
case 2:
printf("\n");
ContactDel(&con);
printf("\n");
continue;
case 3:
printf("\n");
ContactModify(&con);
printf("\n");
continue;
case 4:
printf("\n");
ContactFind(&con);
printf("\n");
continue;
case 5:
printf("\n");
ContactShow(&con);
printf("\n");
continue;
default:
printf("选择不对,请重新选择\n");
printf("\n");
}
} while(input);
ContactDestroy(&con);
}
int main()
{
//text();
menu();
//ContactTest01();
return 0;
}