一:文件声明
在这里我们还是分为三个文件 Contact.h Contact.h Test.c 文件。分别存放通讯录的头文件,源文件,和测试通讯录的功能
二:Contact.h 文件的讲述
在这个文件我们对通讯录的一些基本信息进行封装,既然是通讯录那就要有 姓名 年龄 性别 手机号码 和 家庭住址。我们对其封装成一个结构体,定义为pepInfo 。至于字符数组的大小,采用宏进行定义,这样也方便后期修改。我们以顺续表为底层,进而开发通讯录,所以要进行一个前置声明。就相当于是将顺续表导入。然后把Seqlsit改个名字 运用typedef关键字进行修改为Contact。剩下的就是把增删查改 初始化 和销毁进行声明。然后在Contact.c文件进行实现。
#pragma once
#define NAME_MAX 20
#define GENDER_MAX 10 //male female
#define TEL_MAX 15
#define ADDR_MAX 100
//定义结构体
//姓名 性别 年龄 电话 住址
typedef struct personInfo
{
char name[NAME_MAX];
char gender[GENDER_MAX];
int age;
char tel[TEL_MAX];
char address[ADDR_MAX];
}pepInfo;
//进行前置声明
struct SeqList;
//顺续表改名字 进行前置声明
typedef struct SeqList Contact; //易错点
//通讯录初始化
void ContactInit(Contact* con);
//通讯录销毁
void ContactDestory(Contact* con);
//通讯录添加数据
void ContactAdd(Contact* con);
//通讯录删除数据
void ContactDel(Contact* con);
//通讯录的修改
void ContactModify(Contact* con);
//通讯录的查找
void ContactFind(Contact* con);
//通讯录的展示
void ContactShow(Contact* con);
三:Contact.c文件实现(通讯录的功能)
首先要包含头文件,可以对里面的方法进行一个调用。然后就是实现各个方法的功能。
1:通讯录的初始化
由于是以顺序表为基础去实现通讯录的,所以要去调用顺续表的一些方法去实现。这样可以大大减少重复的代码。那也就是说通讯录的初始化就相当于是顺序表的初始化,所以直接调用顺续表的初始化方法即可。
2:通讯录的销毁
还是和上面一样,直接调用顺续表的销毁方法。
3:通讯录添加数据
既然是添加数据那就要思考,我们的数据是以人为导向的。所以在这里要创建对象,然后用printf语句和scanf语句进行提示用户和从键盘进行一个录入。(注意:年龄需要取地址,因为是int类型 然后数组名不用取地址,因为数组名本身就是地址)。当这些准备工作做好了之后,采用尾插进行数据的插入。最后联系人添加成功后我们进行提示。
4:检查联系人是否存在
添加完联系人后,我们需要对其进行检验。既然是检验,那就要有一个标准(年龄或者是电话号码),在这里我们用联系人的名字作为查找的一个标准,当用户输入一个名字后,方法就会对其进行查找,这里我们采用for循环进行名字的一个遍历,如果找到了就返回i 的下标结束程序的执行,如果遍历了一遍还是没有找找到那就返回-1。
5:删除联系人
首先创建一个name的一个字符数组,让用户进行名字的输入。然后去判断我们已经存在的名字里面有没有这个人,如果没有那用printf进行提示,如果有直接调用删除的方法即可。
6:通讯录的展示
用户添加完数据后,想要看到已经添加的数据,那就要调用这个方法。首先应该制作一个表头,把姓名 年龄 性别 电话 住址 这些信息都打印出来借助printf语句,然后进行通讯录的遍历,在遍历的过程中把已经存储的信息打印出来。
7:通讯录的修改
首先创建字符数组,然后输入名字,代表我们要修改这个人的信息。先是进行一个判断看看这个人是否在我们已经存储好了的通讯录里面的人,如果不是,进行一个提示该联系人不存在。如果存在则进行一些列的信息提示然后利用scanf语句进行修改。最后提示修改成功。
8:查找联系人
一上来还是先创建字符数组,然后对名字进行输入。如果名字不存在则直接进行提示,如果名字存在直接打印对应的信息即可。(这里的打印[find]这里面的方括号是以find为索引的也就是以我们的查找函数的那个为一个导向)
#define _CRT_SECURE_NO_WARNINGS 1
#include"Contact.h"
#include"SeqList.h"
//实现通讯录的方法
//通讯录的初始化
void ContactInit(Contact* con)
{
//实际是对顺续表进行初始化
SLInit(con);
}
//通讯录的销毁
void ContactDestory(Contact* con)
{
SLDestory(con);
}
//通讯录增加
void ContactAdd(Contact* con)
{
pepInfo 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.address);
//采用尾插
SLPushBack(con, info);
printf("联系人添加成功\n");
}
//检查联系人是否存在
int FindByName(Contact* con, char name[])
{
for (int i = 0; i < con->size; i++)
{
if (0 == strcmp(con->arr[i].name, name))
{
//联系人存在
return i;
}
}
//联系人不存在
return -1;
}
//删除联系人
void ContactDel(Contact* con)
{
//检查联系人是否存在
char name[20];
printf("请输入要删除的联系人:\n");
scanf("%s", name);
int find = FindByName(con, name);
if (find < 0)
{
printf("联系人不存在\n");
}
//联系人存在
SLErase(con, find);
printf("删除成功\n");
}
//通讯录的展示
void ContactShow(Contact* con)
{
//表头
printf("%s %s %s %s %s\n", "姓名", "性别 ", "年龄", "电话", "地址");
for (int i = 0; i < con->size; i++)
{
printf("%s %s %d %s %s\n",
con->arr[i].name,
con->arr[i].gender,
con->arr[i].age,
con->arr[i].tel,
con->arr[i].address
);
}
}
//通讯录的修改
void ContactModify(Contact* con)
{
char name[NAME_MAX];
printf("请输入要修改的名字\n");
scanf("%s", name);
int find = FindByName(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].address);
printf("修改成功\n");
}
//联系人的查找
void ContactFind(Contact* con)
{
char name[NAME_MAX];
printf("请输入要查找人的姓名\n");
scanf("%s", name);
int find = FindByName(con, name);
if (find < 0)
{
printf("要查找的联系人不存在\n");
return; //方法结束
}
//查找的联系人存在
printf("%s %s %s %s %s\n", "姓名", "性别 ", "年龄", "电话", "地址");
printf("%s %s %d %s %s\n",
con->arr[find].name,
con->arr[find].gender,
con->arr[find].age,
con->arr[find].tel,
con->arr[find].address
);
}
四:test.c 测试文件实现
我们要将通讯录封装成一个小项目。首先进行顺续表的一个对象创建其次进行调用顺续表中的方法,进行通讯录的初始化。既然是实现通讯录,那必然要有一个菜单(这里大家看代码即可,不做过多的赘述)。菜单制作好了,我们利用do-while()循环结构将菜单进行一个打印,然后提示用户请输入,(在循环的外面还要定义一个变量)当用户输入完之后,利用switch()选择语句进行各个方法的调用即可。最后结束时不要忘记将通讯录销毁。
#define _CRT_SECURE_NO_WARNINGS 1
#include"Contact.h"
#include"SeqList.h"
void menu()
{
printf("******************************************\n");
printf("******* 1 添加联系人 2 删除联系人 ********\n");
printf("******* 3 修改联系人 4 查找联系人 ********\n");
printf("******* 5 展示联系人 0 退出 ********\n");
printf("******************************************\n");
}
int main()
{
//SLTest01();
//SLtest2();
//ContactTest();
int op = 0;
//创建对象
Contact con;
ContactInit(&con);
do
{
menu();
printf("请输入对应的操作数\n");
scanf("%d", &op);;
switch (op)
{
case 1:
ContactAdd(&con);
break;
case 2:
ContactDel(&con);
break;
case 3:
ContactModify(&con);
break;
case 4:
ContactFind(&con);
break;
case 5:
ContactShow(&con);
break;
case 0:
printf("退出成功\n");
break;
default:
printf("输入错误,重新输入\n");
break;
}
} while (op != 0);
//通讯录的销毁
ContactDestory(&con);
return 0;
}
五:SeqList.h文件回顾(接上一篇)
#pragma once
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
#include"Contact.h"
#include<string.h>
//顺续表的创建
typedef pepInfo SLDataType;
typedef struct SeqList
{
SLDataType* arr;
int size; //容量
int capacity; //存储数据的大小
}SL;
//顺续表的初始化
void SLInit(SL* ps);
//顺续表的销毁
void SLDestory(SL* ps);
//扩容方法
//void SlCheckCapacity(SL* ps);
//顺续表的尾部插入
void SLPushBack(SL* ps, SLDataType x);
//顺续表的头部插入
void SLPushFront(SL* ps, SLDataType x);
//顺续表的尾部删除
void SLPopBack(SL* ps);
//顺续表的头部删除
void SLPopFront(SL* ps);
//在指定位置进行删除和修改
void SLInsert(SL* ps, int pos, SLDataType x);
//删除指定位置的数据
void SLErase(SL* ps, int pos);
//顺续表的查找
int SLFind(SL* ps, SLDataType x);
//顺续表的打印
void SLprint(SL s);
六:SeqList.c文件回顾(接上一篇)
#define _CRT_SECURE_NO_WARNINGS 1
#include"SeqList.h"
顺续表的初始化
void SLInit(SL* ps)
{
ps->arr = NULL;
ps->size = ps->capacity = 0;
}
//顺续表的销毁
void SLDestory(SL* ps)
{
if (ps->arr)
{
free(ps->arr);
}
ps->arr = NULL;
ps->size = ps->capacity = 0;
}
//扩容函数
void SlCheckCapacity(SL* ps)
{
assert(ps);
//检查是否需要申请空间
if (ps->capacity == ps->size)
{
//需要申请空间 根据数学公式 需要成倍的增加空间 有利用程序的执行效果
int newcapacity = ps->capacity == 0 ? 4 : 2 * ps->capacity;
//强制类型转换
SLDataType* tmp = (SLDataType*)realloc(ps->arr, newcapacity * sizeof(SLDataType));
//判断SLDataType*为空指针的情况
if (tmp == NULL)
{
perror("error exit");
exit(1); //实现程序的退出
}
//走到这里代表可以增容
ps->capacity = newcapacity;
ps->arr = tmp;
}
}
//尾部插入
void SLPushBack(SL* ps, SLDataType x)
{
//断言指针
//assert(ps);
//if (ps->capacity == ps->size)
//{
// //申请空间
// int newcapacity = ps->capacity == 0 ? 4 : 2 * sizeof(SLDataType);
// SLDataType* tmp =(SLDataType*)realloc(ps->arr, ps->capacity * 2 * sizeof(SLDataType));
// if (tmp == NULL)
// {
// perror("realloc fail!");
// exit(1);//退出程序
// }
// //空间申请成功
// ps->capacity = newcapacity;
// ps->arr = tmp;
//}
//进行数据的插入
SlCheckCapacity(ps);
ps->arr[ps->size++] = x;
}
//头部插入
void SLPushFront(SL* ps, SLDataType x)
{
SlCheckCapacity(ps);
//让数组中的元素整体向后挪动一位
for (int i = ps->size; i > 0; i--)
{
ps->arr[i] = ps->arr[i - 1]; //arr[1]=arr[0]
}
//插入数据
ps->arr[0] = x;
ps->size++; //注意 这是易错点
}
//尾部删除
void SLPopBack(SL* ps)
{
assert(ps);
assert(ps->size);
//ps->arr[ps->size--] = -1;
--ps->size; //在顺续表不为空的情况下进行size的--
}
//头部删除
void SLPopFront(SL* ps)
{
assert(ps);
assert(ps->arr);
for (int i = 0; i < ps->size - 1; i++)
{
ps->arr[i] = ps->arr[i + 1]; //整体向后挪动一位
}
ps->size--;
}
//在指定位置之前进行插入数据
void SLInsert(SL* ps, int pos, SLDataType x)
{
assert(ps);
assert(pos >= 0 && pos <= ps->size);
//检查循序表的容量
SlCheckCapacity(ps);
for (int i = ps->size; i > pos; i--)
{
//数据整体向后挪动
ps->arr[i] = ps->arr[i - 1];
}
ps->arr[pos] = x;
ps->size++;
}
//在指定位置删除
void SLErase(SL* ps, int pos)
{
//指针有效性
assert(ps);
assert(pos >= 0 && pos < ps->size);
for (int i = pos; i < ps->size - 1; i++)
{
//从pos向后整体向后挪动一位
ps->arr[i] = ps->arr[i + 1];
}
ps->size--;
}