一、前言
基于已经学过的顺序表,可以实现一个简单的通讯录。
二、通讯录相关头文件
//Contact.h
#pragma once
#define NAME_MAX 20
#define TEL_MAX 20
#define ADDR_MAX 20
#define GENDER_MAX 20
typedef struct PersonInfo
{
char name[NAME_MAX];
char gender[GENDER_MAX];
int age;
char tel[TEL_MAX];
char addr[ADDR_MAX];
}PsInFo;
//struct SeqList;//前置声明
typedef struct SeqList Contact;//对顺序表重命名为通讯录
//通讯录的初始化
void ContactInit(Contact* pcon);
//通讯录的销毁
void ContactDestroy(Contact* pcon);
//添加联系人
void ContactAdd(Contact* pcon);
//删除联系人
void ContactDel(Contact* pcon);
//查找联系人
void ContactFind(Contact* pcon);
//修改联系人
void ContactModify(Contact* pcon);
//展示联系人
void ContactShow(Contact* pcon);
上述代码中结构体是我们自己定义的通讯录中联系人的基本信息,通讯录中的联系人就相当于是顺序表中的一个个数据,而通讯录就相当于是顺序表;
至于后面两行代码(前置声明和重命名)需要结合以下代码来理解
//SeqList.h
#pragma once
//顺序表
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
//引用通讯录的头文件来对数据类型进行重命名
#include"Contact.h"
typedef PsInFo SeqDatatype;
typedef struct SeqList
{
SeqDatatype* arr;
int size;
int capacity;
}SL;
//初始化顺序表
void SeqInit(SL* ps);
//销毁顺序表
void SeqDestroy(SL* ps);
//顺序表尾插
void SeqPushBack(SL* ps, SeqDatatype x);
//申请空间
void SeqCheckSpace(SL* ps);
//打印顺序表的元素
void SeqPrint(SL* ps);
//顺序表头插
void SeqPushFront(SL* ps, SeqDatatype x);
//顺序表尾删
void SeqPopBack(SL* ps);
//顺序表头删
void SeqPopFront(SL* ps);
//指定位置前插入数据
void SeqInsert(SL* ps, int pos, SeqDatatype x);
//删除指定位置的数据
void SeqErase(SL* ps, int pos);
//寻找数据(以下标的形式返回)
//int SeqFind(SL s, SeqDatatype x);
这是顺序表的头文件,我们为了将联系人PsInFo定义为新的数据类型需要引用Contact.h的头文件,这是因为联系人是在Contact.h中定义的;所以现在回到第一段本文展示的代码中的那两行代码(前置声明和重命名),我们为了让SeqList等同于Contact,需要重命名,但是此时要使用SeqList不能直接包含SeqList.h这个头文件,这时因为头文件不能互相包含,此时我们需要进行前置声明,也就是struct SeqList; 可以直接结合起来写成typedef struct SeqList Contact;
值得注意的是,这里不能写成typedef SL Contact;因为这相当于没有进行前置声明。解释:虽然在顺序表头文件中,typedef strcut SeqList{·······}SL 看似是结构体和SL一起定义的,但实际上是结构体先定义的,也就是说,在这个结构体未定义的时候就使用SL是非法的,在Contact.h中写成typedef SL Contact; 就是遇到了这种错误,所以要进行前置声明,这样就能规避这种问题。
三、通讯录的具体实现
1、初始化
//初始化通讯录
void ContactInit(Contact* pcon)
{
assert(pcon);
SeqInit(pcon);
}
2、销毁
//通讯录销毁
void ContactDestroy(Contact* pcon)
{
assert(pcon);
SeqDestroy(pcon);
}
3、添加联系人
//添加联系人
void ContactAdd(Contact* pcon)
{
assert(pcon);
SeqCheckSpace(pcon);
PsInFo info;//定义一个联系人
printf("输入联系人姓名:\n");
scanf("%s", info.name);
printf("输入联系人性别:\n");
scanf("%s", info.gender);
printf("输入联系人年龄:\n");
scanf("%d", &info.age);
printf("输入联系人电话:\n");
scanf("%s", info.tel);
printf("输入联系人地址:\n");
scanf("%s", info.addr);
SeqPushBack(pcon,info);
}
把联系人当成顺序表中的数据,先把这个数据赋予确定的数值,在这里相当于是给联系人输入一个个属性(姓名、性别、年龄······),最后进行顺序表尾插的操作;
4、返回联系人下标
int FindByName(Contact* pcon,char name[])
{
for (int i = 0; i < pcon->size; i++)
{
if (strcmp(name, pcon->arr[i].name)==0)
{
return i;
}
}
return -1;
}
这个函数是通过姓名比较的方式来返回即将进行一系列操作的联系人的下标
5、删除联系人
//删除联系人
void ContactDel(Contact* pcon)
{
assert(pcon);
assert(pcon->size);
char name[NAME_MAX];
printf("输入要删除的联系人姓名:\n");
scanf("%s", name);
int rsl=FindByName(pcon,name);
if (rsl == -1)
{
printf("你要删除的联系人不存在\n");
}
else
{
SeqErase(pcon, rsl);
}
}
首先判断这个通讯录里面有没有联系人,没有联系人则断言错误,无法删除。接着要输入一个联系人姓名,再在通过FindByName这个通讯录里面进行遍历看是否有没有这个联系人,如果没有接收到错误的下标,进行不了后续操作;找到了返回这个姓名的联系人的下标,然后使用SeqErase删除这个下标处的联系人;
6、查找联系人
//查找联系人
void ContactFind(Contact* pcon)
{
assert(pcon);
char name[NAME_MAX];
printf("输入要查找的联系人姓名:\n");
scanf("%s", name);
int rsl = FindByName(pcon, name);
if (rsl == -1)
{
printf("你要查找的联系人不存在\n");
}
else
{
printf("%s""%s""%s""%s""%s", "姓名 ", "性别 ", "年龄 ", "电话 ", "地址 ");
printf("\n");
printf("%s ""%s ""%d ""%s ""%s ",
pcon->arr[rsl].name,
pcon->arr[rsl].gender,
pcon->arr[rsl].age,
pcon->arr[rsl].tel,
pcon->arr[rsl].addr);
printf("\n");
}
}
查找联系人不同于返回联系人下标,它要展示出所查找的这个联系人的相关信息;
7、修改联系人信息
//修改联系人
void ContactModify(Contact* pcon)
{
assert(pcon);
char name[NAME_MAX];
printf("输入要修改信息的联系人姓名:\n");
scanf("%s", name);
int rsl = FindByName(pcon, name);
if (rsl == -1)
{
printf("你要修改信息的联系人不存在\n");
}
else
{
printf("开始输入新的联系人信息\n");
printf("输入联系人姓名:\n");
scanf("%s", pcon->arr[rsl].name);
printf("输入联系人性别:\n");
scanf("%s", pcon->arr[rsl].gender);
printf("输入联系人年龄:\n");
scanf("%d", &pcon->arr[rsl].age);
printf("输入联系人电话:\n");
scanf("%s", pcon->arr[rsl].tel);
printf("输入联系人地址:\n");
scanf("%s", pcon->arr[rsl].addr);
}
}
同样的,先通过姓名的比较来判断该联系人存不存在,若是有则重新在此联系人下标处出入相关信息;
8、展示联系人
//展示联系人
void ContactShow(Contact* pcon)
{
assert(pcon);
printf("%s""%s""%s""%s""%s", "姓名 ", "性别 ", "年龄 ", "电话 ", "地址 ");
printf("\n");
for (int i = 0; i < pcon->size; i++)
{
printf("%s ", pcon->arr[i].name);
printf("%s ", pcon->arr[i].gender);
printf("%d ", pcon->arr[i].age);
printf("%s ", pcon->arr[i].tel);
printf("%s ", pcon->arr[i].addr);
printf("\n");
}
}
通过遍历通讯录来展翅一个一个联系人的相关信息。
四、设置操作面板
#include"Contact.h"
#include"SeqList.h"
void menu()
{
printf("********** 1.增加联系人**********\n");
printf("********** 2.删除联系人**********\n");
printf("********** 3.查找联系人**********\n");
printf("********** 4.修改联系人**********\n");
printf("********** 5.展示联系人**********\n");
printf("********** 6.销毁通讯录**********\n");
printf("********** 0.退出 **********\n");
}
int main()
{
menu();
Contact con;
ContactInit(&con);
int option = -1;
do
{
printf("输入操作数:\n");
scanf_s("%d", &option);
switch (option)
{
case 1:
ContactAdd(&con);
break;
case 2:
ContactDel(&con);
break;
case 3:
ContactFind(&con);
break;
case 4:
ContactModify(&con);
break;
case 5:
ContactShow(&con);
break;
case 6:
ContactDestroy(&con);
break;
case 0:
printf("退出\n");
return;
default:
printf("输入错误,重新选择\n");
}
} while (option);
return 0;
}
完。