一、通讯录功能
1、保存1000个人的信息
(1)一个人的信息包括:名字、性别、年龄、电话、住址
2、增加联系人
3、删除联系人
4、修改联系人
5、查找联系人
6、排序
7、打印通讯录已有成员的信息
二、通讯录实现要求
1、采用多模块方式实现:
(1)测试模块:专门测试通讯录的功能。
test.c
(2)通讯录模块:实现通讯录的功能。
contact.h --- 接口的声明
contact.c --- 接口的实现
(3)类型的声明、函数的声明一般都放在头文件中。使用的时候只需引头文件。
三、通讯录的实现
1、整体的框架
(1)在test.c源文件下有test()函数,用来实现功能的选择:
//一般写法
void test()
{
int input = 0;
do
{
menu();//选择功能
printf("请选择所需的功能:>");
scanf("%d", &input);
switch (input)
{
case 1:
add();
break;
case 2:
del();
break;
case 3:
search();
break;
case 4:
modify();
break;
case 5:
sort();
break;
case 0:
printf("退出通讯录\n");
break;
default:
printf("输入错误,请重新输入:>\n");
}
} while (input);
}
也可以:使用枚举列举出通讯录功能的可能取值,在switch…case…语句中,直接使用枚举常量,提高代码的可读性。(也可以不使用枚举,就采用1,2,3…如正上方代码)
enum option
{
EXIT,//默认0
ADD,//默认1
DEL,
SEARCH,
MODIFY,
SORT,
PRINT
};
//使用枚举
void test()
{
int input = 0;
Contact con;//通讯录
do
{
menu();//选择功能
printf("请选择所需的功能:>");
scanf("%d", &input);
switch (input)
{
case ADD:
AddContact();
break;
case DEL:
del();
break;
case SEARCH:
search();
break;
case MODIFY:
modify();
break;
case SORT:
sort();
break;
case PRINT:
print();
break;
case EXIT:
printf("退出通讯录\n");
break;
default:
printf("输入错误,请重新输入:>\n");
}
} while (input);
}
(2)在test()函数里调用menu()函数,打印菜单。
void menu()
{
printf("**************************\n");
printf("****1.add 2.del ******\n");
printf("****3.search 4.modify****\n");
printf("****5.sort 6.print ****\n");
printf("****0.exit ****\n");
printf("**************************\n");
}
(3)创建通讯录
- 直接使用 PeoInfo 创建data[1000] 数组,存放1000个人的信息。但考虑到打印已有成员信息时要记录已有成员的个数,创建变量 sz,记录通讯录中已经保存的信息个数。为了传参方便,直接将data[1000] 与 sz 放在结构体Contact中,传参的时候只需传Contact。
typedef struct Contact
{
PeoInfo data[1000];//创建通讯录,可以保存1000个人的信息
int sz;//记录通讯录中已经保存的信息个数
}Contact;
- 在test()函数中 创建通讯录
Contact con;
2、保存1000个人的信息
(1)一个人的信息包括:名字、性别、年龄、电话、住址
//声明通讯录人的信息
typedef struct PeoInfo
{
char name[20];
char sex[5];
int age;
char tele[12];//电话一般十一位
char addr[30];
}PeoInfo;
(2)保存1000个人的信息
//创建包含1000个元素的数组
PeoInfo data[1000];//存放1000个人的信息
(3)补充:为了方便后期修改常数,直接define声明常量
#define MAX 1000
#define NAME_MAX 20
#define SEX_MAX 5
#define TELE_MAX 12
#define ADDR_MAX 30
typedef struct PeoInfo
{
char name[NAME_MAX];
char sex[SEX_MAX];
int age;
char tele[TELE_MAX];//电话一般十一位
char addr[ADDR_MAX];
}PeoInfo;
typedef struct Contact
{
PeoInfo data[MAX];//创建通讯录,可以保存1000个人的信息
int sz;//记录通讯录中已经保存的信息个数
}Contact;
3、初识化通讯录
(1)解释:在首次增加联系人前要将通讯录初始化,将sz初始化为0;将data[1000]中每个元素都初始化为0.
(2)初始化的实现
- 函数参数Contact* pc ,是一个结构体指针,接收 con 的地址。
- pc->data 此时data相当于数组的首元素,pc->data相当于data数组的起始地址。
- memset( )函数—内存设置函数,记得添加头文件<string.h>
void* memset(void* dest,int c,size_t count);
void* dest 起始地址;
int c 需要被改成的值;
size_t count 需要修改的范围(以字节为单位)。
memset 是以字节为单位来初始化内存单元的。
//初始化通讯录
void InitContact(Contact* pc)
{
memset(pc->data,0,sizeof(pc->data));
pc->sz = 0;
}
4、增加联系人
- 记得判断通讯录是否已满
void AddContact(Contact* pc)
{
if (pc->sz == MAX)
{
printf("通讯录已满,无法添加\n");
return;
}
//录入信息
printf("请输入名字:>");
scanf("%s", pc->data[pc->sz].name);
printf("请输入性别:>");
scanf("%s", pc->data[pc->sz].sex);
printf("请输入年龄:>");
scanf("%d", &(pc->data[pc->sz].age));
printf("请输入电话:>");
scanf("%s", pc->data[pc->sz].tele);
printf("请输入地址:>");
scanf("%s", pc->data[pc->sz].addr);
pc->sz++;
printf("添加成功\n");
}
5、删除联系人
(1)首先判断通讯录是否为空,为空的话,就没必要删除。
(2)删除联系人包括两步:
-
找到指定的联系人
//1.先定义一个数组,存放指定人的信息 //2.输入姓名(假设没有重名现象) //3.使用strcmp()来比较输入的名字与data数组中联系人的名字,当strcmp返回值为0时,表示两个字符串相等,此时返回下标。而查找指定联系人在其他功能处也要使用,所以写成函数,使用时直接调用。
//查找指定联系人 int FindByName(Contact* pc, char name[]) { assert(pc); int i = 0; for (i = 0; i < pc->sz; i++) { if (0 == strcmp(pc->data[i].name, name))//等于0表示两个字符串相等 { return i; } } return -1; }
-
删除指定联系人
//删除指定联系人的思想: //1.获取到指定联系人的下标(在找到指定联系人步骤中已经得到) //2.将它下标的下一位对应的元素赋值给它,此步骤相当于将其覆盖,然后依次覆盖。使用for循环实现。
//删除指定联系人
void DelContact(Contact* pc)
{
assert(pc);
if (pc->sz == 0)
{
printf("通讯录已空,无法删除\n");
}
//删除
//1.找到指定联系人
char name[NAME_MAX] = { 0 };
printf("请输入要查找的联系人姓名:>");
scanf("%s", name);
int pos=FindByName(pc, name);
if (pos == -1)
{
printf("要删除的人不存在\n");
return;
}
//2.删除
int j = 0;
for (j = pos; j < pc->sz-1; j++) //假设j最大是999,那么j+1就是1000,越界,所以sz-1
{
pc->data[j] = pc->data[j + 1];
}
pc->sz--;
printf("删除成功\n");
}
6、修改联系人
//修改指定联系人
void ModifyContact(Contact* pc)
{
char name[NAME_MAX] = { 0 };
printf("请输入要查找的联系人姓名:>");
scanf("%s", name);
int pos = FindByName(pc, name);
if (pos == -1)
{
printf("要查找的人不存在\n");
return;
}
printf("请输入修改后的姓名:>");
scanf("%s", pc->data[pos].name);
printf("请输入修改后性别:>");
scanf("%s", pc->data[pos].sex);
printf("请输入修改后年龄:>");
scanf("%d", &(pc->data[pos].age));
printf("请输入修改后电话:>");
scanf("%s", pc->data[pos].tele);
printf("请输入修改后地址:>");
scanf("%s", pc->data[pos].addr);
printf("修改成功\n");
printf("%-20s %-5s %-5s %-12s %-30s\n", "姓名", "性别", "年龄", "电话号码", "地址");
printf("%-20s %-5s %-5d %-12s %-30s\n", pc->data[pos].name,
pc->data[pos].sex, pc->data[pos].age, pc->data[pos].tele,
pc->data[pos].addr);//左对齐的效果
}
7、查找联系人
(1)通过姓名查找指定联系人,找到后返回下标。
(2)打印找到的联系人。
//查找联系人
void SearchContact(const Contact* pc)
{
char name[NAME_MAX] = { 0 };
printf("请输入要查找的联系人姓名:>");
scanf("%s", name);
int pos = FindByName(pc, name);
if (pos == -1)
{
printf("要查找的人不存在\n");
return;
}
printf("%-20s %-5s %-5s %-12s %-30s\n", "姓名", "性别", "年龄", "电话号码", "地址");
printf("%-20s %-5s %-5d %-12s %-30s\n", pc->data[pos].name,
pc->data[pos].sex, pc->data[pos].age, pc->data[pos].tele,
pc->data[pos].addr);//左对齐的效果
}
8、排序
(1)思路:按照姓名排序,使用strcmp()函数,比较姓名;使用qsort()函数进行排序,但要自定义比较函数。
(2)qsort的使用:
void qsort( void *base, size_t num, size_t width, int (__cdecl *compare )(const void *elem1, const void *elem2 ) 需要自定义比较函数,函数的参数是void*类型,即为需要排序的两个元素的地址。函数的返回类型是int );
//void *base 起始元素地址
//size_t num 元素个数
//size_t width 元素大小
//int (__cdecl *compare )(const void *elem1, const void *elem2 ) 指针函数
//需要自定义比较函数,函数的参数是void*类型,即为需要排序的两个元素的地址。函数的返回类型是int
//只需要给qsort提供以上四种参数,qsort就会自动排序,只不过其中的第四个参数要自定义。
int cmp_by_name(const void* e1, const void* e2)
{
return strcmp(((PeoInfo*)e1)->name, ((PeoInfo*)e2)->name);
}
void SortContact(Contact* pc)
{
qsort(pc->data, pc->sz, sizeof(PeoInfo), cmp_by_name);
printf("排序成功\n");
}
9、打印
- 直接for循环,挨个输出data数组中的元素。
//打印已有信息
void PrintContact(const Contact* pc)
{
assert(pc);
int i = 0;
printf("%-20s %-5s %-5s %-12s %-30s\n", "姓名", "性别", "年龄", "电话号码", "地址");
for (i = 0; i < pc->sz; i++)
{
//printf("%20s %5s %5d %12s %30s\n", pc->date[i].name,
// pc->date[i].sex, pc->date[i].age, pc->date[i].tele,
// pc->date[i].addr);//右对齐的效果
printf("%-20s %-5s %-5d %-12s %-30s\n", pc->data[i].name,
pc->data[i].sex, pc->data[i].age, pc->data[i].tele,
pc->data[i].addr);//左对齐的效果
}
}