目录
一、通讯录设计思路
1. 伪代码设计思路
通讯录可以用来存储 100 个人的信息,每个人的信息包括:姓名、性别、年龄、电话、住址。
提供方法:
- 添加联系人信息
- 删除指定联系人信息
- 查找指定联系人信息
- 修改指定联系人信息
- 显示所有联系人信息
- 清空所有联系人
- 以名字排序所有联系人
2. 代码设计思路
通过对上述伪代码的分析,我们使用结构体 info_person 来表示个人信息。
c
// 个人信息结构声明
typedef struct info_person
{
char name[20]; // 姓名
char sex[5]; // 性别
size_t age; // 年龄
char phone[12]; // 电话
char address[40]; // 住址
}info_person;
接着再使用一个结构体 ContacksList 来表示通讯录,该通讯录包含一个结构体 info_person 数组,大小为 100,用来存储 100 个人的信息。此外还应该包含一个 size_t 类型的成员 size 用来表示当前存储个人信息的数量,这也方便了上述伪代码中要求的方法设计。
c
// 常量声明
#define SIZE_INFO 100
// 通讯录结构声明
typedef struct ContacksList
{
info_person infos[SIZE_INFO];
size_t size;
}ContacksList;
下面就是使用有意义的函数名来表示上述方法。
c
// 方法
// 1. 添加联系人信息
void AddContack(ContacksList* cl);
// 2. 删除指定联系人信息
void DeleteContack(ContacksList* cl, char* name);
// 3. 查找指定联系人信息
void FindContack(const ContacksList* cl, char* name);
// 4. 修改指定联系人信息
void ModifyContack(ContacksList* cl, char* name);
// 5. 显示所有联系人信息
void PrintContack(const ContacksList* cl);
// 6. 清空所有联系人
void ClearContack(ContacksList* cl);
// 7. 以名字排序所有联系人
void SortByName(ContacksList* cl);
以上就是头文件 ContacksList.h 包含的基本内容,剩下的就是方法的实现和代码的测试。
二、代码实现
整体代码分成三个文件:头文件 ContacksList.h,方法定义文件 ContacksList.c,测试文件 test.c。由于头文件在前面已经给出,下面就只给出剩下两个文件。
方法定义文件 ContacksList.c
c
// 头文件
#include "ContacksList.h"
#include <assert.h>
#include <string.h>
// 方法
// 1. 添加联系人信息
void AddContack(ContacksList* cl)
{
assert(cl);
// 通讯录已满
if (CAPACITY == cl->size)
{
printf("通讯录已满,添加失败!\n");
return;
}
// 添加
//
// 输入联系人的相关信息
info_person tmp;
printf("请输入联系人的信息->");
printf("姓名: ");
scanf("%s", tmp.name);
printf("性别: ");
scanf("%s", tmp.sex);
printf("年龄: ");
scanf("%zd", &tmp.age);
printf("电话: ");
scanf("%s", tmp.phone);
printf("地址: ");
scanf("%s", tmp.address);
// 拷贝
cl->infos[cl->size] = tmp;
// 人数 +1
++cl->size;
printf("添加成功!\n");
}
// 2. 删除指定联系人信息
void DeleteContack(ContacksList* cl)
{
assert(cl);
// 删除
//
// 查找指定联系人
char name[20];
printf("请输入删除人的姓名: ");
scanf("%s", name);
int i = FindContack(cl, name);
// 找到了
if (-1 != i)
{
// 把该位置往后的联系人往前移
while (i < cl->size - 1)
{
// 前移
cl->infos[i] = cl->infos[i + 1];
// 下一个
++i;
}
// 联系人 -1
--cl->size;
printf("删除成功!\n");
}
else
{
printf("删除失败!\n");
}
}
// 3. 查找指定联系人信息
int FindContack(const ContacksList* cl, char* name)
{
assert(cl);
// 通讯录为空
if (0 == cl->size)
return -1;
// 输入查找人的姓名
char tmp[20] = { 0 };
if (NULL == name)
{
name = tmp;
printf("请输入查找人的姓名: ");
scanf("%s", name);
}
// 查找
int i;
for (i = 0; i < cl->size; ++i)
{
// 找到
if (strcmp(cl->infos[i].name, name) == 0)
{
return i;
}
}
// 没找到
return -1;
}
// 4. 修改指定联系人信息
void ModifyContack(ContacksList* cl)
{
assert(cl);
// 查找指定联系人
char name[20];
printf("请输入修改人的姓名: ");
scanf("%s", name);
int i = FindContack(cl, name);
// 找到了
if (-1 != i)
{
// 输入联系人修改后的相关信息
info_person tmp;
printf("请输入联系人的信息->");
printf("姓名: ");
scanf("%s", tmp.name);
printf("性别: ");
scanf("%s", tmp.sex);
printf("年龄: ");
scanf("%zd", &tmp.age);
printf("电话: ");
scanf("%s", tmp.phone);
printf("地址: ");
scanf("%s", tmp.address);
// 修改
cl->infos[i] = tmp;
printf("修改成功!\n");
}
else
{
printf("修改失败!\n");
}
}
// 5. 显示所有联系人信息
void PrintContack(const ContacksList* cl)
{
assert(cl);
// 标题行
printf("%-10s%-8s%-8s%-15s%-10s\n", "姓名", "性别", "年龄", "电话", "地址");
// 输出
int i;
for (i = 0; i < cl->size; ++i)
{
printf("%-10s%-8s%-8zd%-15s%-10s\n", cl->infos[i].name, cl->infos[i].sex, cl->infos[i].age, cl->infos[i].phone, cl->infos[i].address);
}
}
// 6. 清空所有联系人
void ClearContack(ContacksList* cl)
{
assert(cl);
// 清空
cl->size = 0;
}
// 7. 以名字排序所有联系人
void SortByName(ContacksList* cl)
{
assert(cl);
// 冒泡排序
int i;
for (i = 0; i < cl->size - 1; ++i)
{
int j;
for (j = 0; j < cl->size - 1 - i; ++j)
{
// 相邻比较
if (strcmp(cl->infos[j].name, cl->infos[j + 1].name) > 0)
{
// 交换
info_person tmp = cl->infos[j];
cl->infos[j] = cl->infos[j + 1];
cl->infos[j + 1] = tmp;
}
}
}
printf("按名字身升序排序成功!\n");
}
测试文件 test.c
c
// 头文件
#include "ContacksList.h"
// 菜单
void menu()
{
printf("****************************************************\n");
printf("***********1. Add 2. Delete *************\n");
printf("***********3. Find 4. Modify *************\n");
printf("***********5. Print 6. Clear *************\n");
printf("***********7. Sort 0. Exit *************\n");
printf("****************************************************\n");
}
int main()
{
// 创建通讯录
ContacksList cl = { {0}, 0 };
// 选择操作
int select = 0;
int i = 0;
do
{
// 菜单
menu();
// 选择
printf("请选择: ");
scanf("%d", &select);
switch (select)
{
case 1:
AddContack(&cl);
break;
case 2:
DeleteContack(&cl);
break;
case 3:
i = FindContack(&cl, NULL);
printf("%-10s%-8s%-8s%-15s%-10s\n", "姓名", "性别", "年龄", "电话", "地址");
printf("%-10s%-8s%-8zd%-15s%-10s\n", cl.infos[i].name, cl.infos[i].sex, cl.infos[i].age, cl.infos[i].phone, cl.infos[i].address);
break;
case 4:
ModifyContack(&cl);
break;
case 5:
PrintContack(&cl);
break;
case 6:
ClearContack(&cl);
break;
case 7:
SortByName(&cl);
break;
case 0:
printf("退出通讯录!\n");
break;
default:
printf("选择错误,请重新选择!\n");
break;
}
} while (select);
return 0;
}
三、程序运行演示
四、整体分析
该通讯录是一个静态通讯录,容量是固定的,当数据超出容量时不够存储,当数据少于容量时造成空间的浪费。后面作者会把该通讯录升级为动态通讯录,当容量不够的时候会进行增容。
在方法实现中,删除指定联系人函数 DeleteContack() 和修改指定联系人函数 ModifyContack() 都需要先找到指定的联系人,所以可以稍微修改一下查找指定联系人函数 FindContack(),然后再前面两个函数中调用该函数,这样就减少了代码的冗余。删除操作需要判断通讯录是否为空,插入操作需要判断通讯录是否已满。
当然读者可以自行根据需要进行修改,这里只提供一个大概思路和基础功能的实现。