本文中,我们将使用顺序表的结构来完成通讯录的实现。
我们都知道,顺序表实际上就是一个数组。而使用顺序表来实现通讯录,其内核是将顺序表中存放的数据类型改为结构体,将联系人的信息存放到结构体中,通过对顺序表的操作来访问通讯录。
所以我们可以将通讯录理解为套壳的顺序表。
一、功能
(1)能够保存联系人的姓名、年龄、性别、电话、住址
(2)添加联系人信息
(3)删除联系人信息
(4)修改联系人信息
(5)查找联系人信息
(6)查看通讯录中所有联系人信息
(7)清空通讯录
(8)每次加载通讯录时自动载入历史通讯录,退出通讯录后自动保存通讯录信息
二、代码实现
实现通讯录我们要创建6个文件来实现不同的部分
- SeqList.h:顺序表定义、头文件引用和顺序表接口函数的声明
- SeqList.c:顺序表接口函数的实现
- Contact.h:信息结构体的定义和通讯录函数的声明
- Contact.c:通讯录函数的实现
- test.c:界面设计和通讯录主函数实现
- contact.txt:在同目录下创建,用来保存通讯录数据实现读档存档
(1) SeqList.h
在实现通讯录函数的时候我们可以套用顺序表的接口函数减少工作量,但是并不是所有顺序表的函数都会用到。下面展示SeqList.h的代码:
#pragma once
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <Windows.h>
#include "Contact.h"
typedef Info SLDataType; //顺序表元素种类为存放个人信息的结构体
typedef struct SeqList
{
SLDataType* a;
size_t size;
size_t capicity;
} SeqList;
// 顺序表初始化
void SeqListInit(SeqList* psl);
// 检查空间,如果满了,进行增容
void CheckCapacity(SeqList* psl);
// 顺序表尾插
void SeqListPushBack(SeqList* psl, SLDataType x);
// 顺序表删除pos位置的值
void SeqListErase(SeqList* psl, size_t pos);
// 顺序表销毁
void SeqListDestory(SeqList* psl);
(2) SeqList.c
SeqList.c的代码如下:
#include "SeqList.h"
void SeqListDestory(SeqList* psl)
{
assert(psl);
free(psl->a);
psl->a = NULL;
psl->capicity = 0;
psl->size = 0;
}
void SeqListInit(SeqList* psl)
{
assert(psl);
psl->a = (SLDataType*)malloc(sizeof(SLDataType) * 4);
if (psl->a == NULL)
{
perror("malloc fail");
return;
}
psl->size = 0;
psl->capicity = 4;
}
void CheckCapacity(SeqList* psl)
{
assert(psl);
if (psl->size == psl->capicity)
{
SLDataType* tmp = (SLDataType*)realloc(psl->a, sizeof(SLDataType) * psl->capicity * 2);
if (tmp == NULL)
{
perror("realloc fail");
return;
}
psl->a = tmp;
psl->capicity *= 2;
}
}
void SeqListPushBack(SeqList* psl, SLDataType x)
{
assert(psl);
CheckCapacity(psl);
psl->a[psl->size++] = x;
}
void SeqListErase(SeqList* psl, size_t pos)
{
assert(psl);
assert(0 <= pos && pos < psl->size);
while (pos < psl->size - 1)
{
psl->a[pos] = psl->a[pos + 1];
pos++;
}
psl->size--;
}
因为二者在前面的顺序表学习中已经写过了,所以直接cv即可
(3) test.c
在实现通讯录函数之前,我们先把通讯录界面和主函数搞定
创建好test.c后,先包含一下头文件
#include "SeqList.h"
再设计一下界面
#include "SeqList.h"
void Menu()
{
printf("****************通讯录******************\n");
printf("****** 1.添加联系人 2.删除联系人 ******\n");
printf("****** 3.修改联系人 4.查找联系人 ******\n");
printf("****** 5.查看通讯录 6.清空通讯录 ******\n");
printf("****** 0.退出通讯录 ******\n");
printf("****************************************\n");
}
主函数如下:
int main()
{
contact con;
InitContact(&con); //初始化通讯录
LoadContact(&con); //加载历史通讯录
int option = -1;
do {
Menu();
printf("请选择:\n");
scanf("%d", &option);
system("cls"); //适当的清屏看起来更简洁
switch (option)
{
case 1:
//添加联系人
AddContact(&con);
break;
case 2:
//删除联系人
DelContact(&con);
break;
case 3:
//修改联系人
ModifyContact(&con);
break;
case 4:
//查找联系人
FindContact(&con);
break;
case 5:
//查看通讯录
ShowContact(&con);
break;
case 6:
//清空通讯录
ClearContact(&con);
break;
case 0:
//退出通讯录
printf("通讯录退出中...\n");
break;
default:
printf("非法操作,请重新输入\n");
break;
}
} while (option);
SaveContact(&con); //保存通讯录
DestoryContact(&con); //销毁通讯录
return 0;
}
(4) Contact.h
界面和主函数都搞定后,我们开始完成通讯录函数并逐个填空到主函数中
下面是Contact.h的代码
#pragma once
#define NAME_MAX 100
#define GENDER_MAX 10
#define TEL_MAX 11
#define ADDR_MAX 100
struct SqeList;
//因为这里不能声明SeqList.h,不然会造成嵌套声明,所以就单独声明一下顺序表
typedef struct SeqList contact;
//要实现的是通讯录,所以得把顺序表换个名,但换汤不换药
typedef struct PersonInfo
{
char name[NAME_MAX]; //姓名
int age; //年龄
char gender[GENDER_MAX]; //性别
char telephone[TEL_MAX]; //电话
char address[ADDR_MAX]; //住址
}Info;
void InitContact(contact* pcon);//初始化通讯录
void DestoryContact(contact* pcon);//销毁通讯录
int FindByName(contact* pcon, char* name);//通过姓名查找联系人
void AddContact(contact* pcon);//添加联系人
void DelContact(contact* pcon);//删除联系人
void ModifyContact(contact* pcon);//修改联系人信息
void FindContact(contact* pcon);//查找联系人
void ShowContact(contact* pcon);//展示联系人列表
void ClearContact(contact* pcon);//清空通讯录
void SaveContact(contact* pcon);//保存通讯录
void LoadContact(contact* pcon);//载入历史通讯录
(5) Contact.c
接下来我们展示Contact.c的完整代码
#include "SeqList.h"
void InitContact(contact* pcon)//初始化通讯录
{
SeqListInit(pcon);
}
void DestoryContact(contact* pcon)//销毁通讯录
{
SeqListDestory(pcon);
}
int FindByName(contact* pcon, char* name)//通过姓名查找联系人
{
for (size_t i = 0; i < pcon->size; i++)
{
if (strcmp(name, pcon->a[i].name) == 0)
{
return i;
}
}
return -1;
}
void AddContact(contact* pcon)//添加联系人
{
CheckCapacity(pcon);
printf("请输入姓名:\n");
scanf("%s", pcon->a[pcon->size].name);
printf("请输入年龄:\n");
scanf("%d", &(pcon->a[pcon->size].age));
printf("请输入性别:\n");
scanf("%s", pcon->a[pcon->size].gender);
printf("请输入电话:\n");
scanf("%s", pcon->a[pcon->size].telephone);
printf("请输入住址:\n");
scanf("%s", pcon->a[pcon->size].address);
pcon->size++;
system("cls");
printf("添加成功!\n");
}
void DelContact(contact* pcon)//删除联系人
{
char name[100];
printf("请输入要删除的联系人:\n");
scanf("%s", name);
int index = FindByName(pcon, name);
if (index == -1)
{
printf("要删除的用户不存在!\n");
return;
}
SeqListErase(pcon, index);
system("cls");
printf("删除成功!\n");
}
void ModifyContact(contact* pcon)//修改联系人信息
{
char name[100];
printf("请输入要修改的联系人:\n");
scanf("%s", name);
int index = FindByName(pcon, name);
if (index == -1)
{
printf("要修改的用户不存在!\n");
return;
}
printf("请输入修改后的姓名:\n");
scanf("%s", pcon->a[index].name);
printf("请输入修改后的年龄:\n");
scanf("%d", &(pcon->a[index].age));
printf("请输入修改后的性别:\n");
scanf("%s", pcon->a[index].gender);
printf("请输入修改后的电话:\n");
scanf("%s", pcon->a[index].telephone);
printf("请输入修改后的住址:\n");
scanf("%s", pcon->a[index].address);
system("cls");
printf("修改成功!\n");
}
void FindContact(contact* pcon)//查找联系人
{
char name[100];
printf("请输入要查找的联系人:\n");
scanf("%s", name);
int index = FindByName(pcon, name);
if (index == -1)
{
printf("要查找的用户不存在!\n");
return;
}
system("cls");
printf("查找成功!\n");
printf("姓名:%s\n", pcon->a[index].name);
printf("年龄:%d\n", pcon->a[index].age);
printf("性别:%s\n", pcon->a[index].gender);
printf("电话:%s\n", pcon->a[index].telephone);
printf("住址:%s\n", pcon->a[index].address);
}
void ShowContact(contact* pcon)//展示联系人列表
{
if (pcon->size == 0)
{
printf("通讯录为空!\n");
return;
}
printf("姓名 年龄 性别 电话 地址\n");
for (size_t i = 0; i < pcon->size; i++)
{
printf("%s %d %s %s %s\n",
pcon->a[i].name,
pcon->a[i].age,
pcon->a[i].gender,
pcon->a[i].telephone,
pcon->a[i].address);
}
}
void ClearContact(contact* pcon)//清空通讯录
{
pcon->size = 0;
printf("通讯录清空成功!\n");
}
void SaveContact(contact* pcon)//保存通讯录
{
FILE* pf = fopen("contact.txt", "wb");
if (pf == NULL)
{
perror("fopen fail");
return;
}
for (size_t i = 0; i < pcon->size; i++)
{
fwrite(pcon->a + i, sizeof(Info), 1, pf);
}
printf("通讯录数据保存成功!\n");
fclose(pf);
}
void LoadContact(contact* pcon)//载入历史通讯录
{
FILE* pf = fopen("contact.txt", "rb");
if (pf == NULL)
{
perror("fopen fail");
return;
}
Info info;
while (fread(&info, sizeof(Info), 1, pf))
{
SeqListPushBack(pcon, info);
}
printf("通讯录数据载入成功!\n");
fclose(pf);
}
三、测试
(1)添加联系人
选择功能
输入联系人信息
我们查看通讯录检查一下是否真的添加成功
按照同样的步骤再添加一个联系人试试
(2)删除联系人
选择功能
输入要删除的联系人姓名
检查一下
确实删除了
(3)修改联系人
选择功能
输入要修改的联系人姓名
输入修改后的信息
修改成功,我们检查一下
(4)查找联系人
选择功能,输入要查找的联系人姓名
(5)清空通讯录
我们试着多添加几个联系人
现在通讯录中有5个联系人,我们选择清空通讯录
再查看通讯录
(6)通讯录读档和存档
向通讯录中添加几个联系人
选择退出通讯录
重新打开程序,选择查看通讯录,发现之前的联系人仍在通讯录中
完.