本章实现一个简单的静态版本的通讯录功能。
功能要求要求:
存放1000个人的信息
信息内容:姓名、性别、年龄、电话、地址
要实现的功能:
0.退出通讯录
1.增加联系人
2.删除联系人
3.查找联系人
4.修改联系人
5.查看所有联系人
6.排序
7.清空通讯录
首先,我们把主体框架构建出来
(1)头文件contact.h中放函数声明、变量定义
因为每个人有多个信息,属于复杂对象,所以我们使用结构体类型来定义;
通讯录不仅要保存1000个联系人的信息,而且要记录当前通讯录中联系人的个数,所以把通讯录定义为结构体类型,有两个成员,一个是数组,用于保存联系人信息,一个是int类型变量,用于记录通讯录中联系人的个数
对于字符数组元素个数,如果写成具体的数值,不方便以后代码的扩展,所以我们使用#define定义标识符常量
//contact.h
#pragma once
#define NAME_MAX 20
#define SEX_MAX 5
#define TELE_MAX 15
#define ADDR_MAX 30
#define MAX 1000
//一个联系人的信息
struct PeopleInfo
{
char name[NAME_MAX];
int age;
char sex[SEX_MAX];
char tele[TELE_MAX];
char addr[ADDR_MAX];
};
//通讯录结构体
struct Contact
{
//1000个人的信息放在数组中
struct PeopleInfo data[MAX];
//当前通讯录联系人的个数
int sz;
};
(2)源文件test.c用来测试代码,
menu()函数,打印菜单,input接收用户选择
定义枚举类型enum Option,枚举常量的值分别代表对应的功能
定义一个通讯录类型变量,并进行初始化
使用do…while循环结构,使用switch…case分支,不同的选择执行不同的功能函数
//test.c #define _CRT_SECURE_NO_WARNINGS 1 #include实现具体功能#include "contact.h" void menu() { printf("*********************************************n"); printf("******** 1.add 2.del **************n"); printf("******** 3.search 4.modify **************n"); printf("******** 5.show 6.sort **************n"); printf("******** 7.clear 0.exit **************n"); printf("*********************************************n"); } enum Option { EXIT, ADD, DEL, SEARCH, MODIFY, SHOW, SORT, CLEAR }; int main() { int input = 0; //创建一个通讯录 struct Contact con; //初始化通讯录 InitContact(&con); do { menu(); printf("请选择:>"); scanf("%d",&input); switch (input) { case ADD: //增加联系人 AddContact(&con); break; case DEL: //删除指定联系人 DelContact(&con); break; case SEARCH: //查找指定联系人 SearchContact(&con); break; case MODIFY: ModifyContact(&con); break; case SHOW: //查看联系人 ShowContact(&con); break; case SORT: //按照姓名排序 SortContact(&con); break; case CLEAR: //清空所有联系人 ClearContact(&con); break; case EXIT: printf("退出通讯录!n"); break; default: printf("选择错误!n"); break; } } while (input); return 0; }
主体框架搭建完成后,我们就来一一实现具体的功能函数
初始化通讯录定义一个通讯录变量后,要对通讯录进行初始化,由于通讯录是结构体类型,如果形参使用结构体,那么要浪费很大内存空间,并且是值传递,不能做到对通讯录的修改,所以形参设计为结构体指针。
此时通讯录中没有联系人,所以con->sz = 0,结构体成员data数组也应初始化为0,这里我们使用memset函数进行初始化。
数组只有在定义时进行初始化,之后不能对数组名直接进行赋值。定义结构体的时候,不能对里面的变量同时初始化。因为定义结构体类型时,并未给其分配内存,所以初值是无法存储的。应该在声明结构体变量后,再赋值。
//contact.c
//初始化通讯录
void InitContact(struct Contact* con)
{
//没有联系人信息
con->sz = 0;
//把data数组初始化为0
//memset(con->data,0,MAX*sizeof(struct PeopleInfo));
memset(con->data,0,sizeof(con->data));
}
增加联系人
首先要判断通讯录是否已经满了,如果满了,那么不能再存放其他联系人信息,给用户提示,如果没满,用户逐一输入信息,然后将信息存入通讯录结构成员data数组中,每增加一人,通讯录中联系人的个数增加1
//contact.c
//增加联系人
void AddContact(struct Contact* con)
{
if (con->sz == MAX)
{
printf("通讯录满了!n");
}
else
{
printf("请输入姓名:>");
scanf("%s", con->data[con->sz].name);
printf("请输入年龄:>");
scanf("%d",&(con->data[con->sz].age));
printf("请输入性别:>");
scanf("%s", con->data[con->sz].sex);
printf("请输入电话:>");
scanf("%s", con->data[con->sz].tele);
printf("请输入地址:>");
scanf("%s", con->data[con->sz].addr);
printf("添加成功!n");
(con->sz)++;
}
}
删除指定联系人
首先要查看通讯录是否为空,如果为空,给用户提示,如果不为空,那么要先判断通讯录中是否有要删除的联系人,如果没有给用户提示,如果联系人存在,那么将该联系人后面的所有联系人向前移动一位
对于查找联系人封装成一个函数,遍历数组data,注意字符串比较使用strcmp函数,不能直接使用==判断是否相等
//查找指定联系人
int FindContact(const struct Contact* con,char name[])
{
//遍历data数组
int i = 0;
for (i = 0; i < (con->sz); i++)
{
if (strcmp(con->data[i].name,name) == 0)
{
return i;
}
}
return -1;
}
//删除指定联系人
void DelContact(struct Contact* con)
{
//通讯录为空
if (con->sz == 0)
{
printf("通讯录为空!n");
return;
}
printf("请输入要删除的联系人姓名:>");
char name[NAME_MAX] = { 0 };
scanf("%s",name);
//查找是否存在该联系人
int ret = FindContact(con,name);
if (ret == -1)
{
printf("该联系人不存在!n");
}
else
{
//删除联系人
//后面的联系人前移
int i = 0;
for (i = ret; i < con->sz - 1; i++)
{
con->data[i] = con->data[i+1];
}
printf("删除成功!n");
con->sz--;
}
}
查找指定联系人
根据用户输入的姓名,查找是否存在,存在则打印联系人信息,不存在给用户提示
void SearchContact(const struct Contact* con)
{
char name[NAME_MAX] = {0};
printf("请输入要查找的联系人的姓名:>");
scanf("%s",name);
int ret = FindContact(con,name);
if (ret == -1)
{
printf("没有该联系人!n");
return;
}
else
{
printf("%15st%5st%8st%15st%30sn", "name", "age", "sex", "tele", "addr");
printf("%15st%5dt%8st%15st%30sn", con->data[ret].name,
con->data[ret].age, con->data[ret].sex, con->data[ret].tele, con->data[ret].addr);
}
}
修改联系人信息
首先判断通讯录是否为空,不为空时,用户输入联系人姓名,查找是否存在该联系人,存在则用户输入修改后的信息,存入通讯录的data数组
void ModifyContact(struct Contact* con)
{
if (con->sz == 0)
{
printf("通讯录为空!n");
return;
}
printf("输入要修改的联系人的姓名:>");
char name[NAME_MAX] = {0};
scanf("%s",name);
int ret = FindContact(con,name);
if (ret == -1)
{
printf("该联系人不存在!n");
}
else
{
printf("请输入姓名:>");
scanf("%s",con->data[ret].name);
printf("请输入年龄:>");
scanf("%d", &(con->data[ret].age));
printf("请输入性别:>");
scanf("%s", con->data[ret].sex);
printf("请输入电话:>");
scanf("%s", con->data[ret].tele);
printf("请输入地址:>");
scanf("%s", con->data[ret].addr);
printf("修改成功!n");
}
}
查看所有联系人信息
遍历通讯录,打印所有联系人信息
void ShowContact(struct Contact* con)
{
//判断是否为空
if (con->sz == 0)
{
printf("通讯录为空!n");
return;
}
//打印标题
printf("%15st%5st%8st%15st%30sn", "name", "age", "sex", "tele", "addr");
int i = 0;
for (i = 0; i sz; i++)
{
printf("%15st%5dt%8st%15st%30sn", con->data[i].name,
con->data[i].age, con->data[i].sex, con->data[i].tele, con->data[i].addr);
}
}
通讯录按姓名排序
这里使用qsort库函数,自定义cmp_by_name()函数,按照姓名进行升序排列
int cmp_by_name(const void* e1,const void* e2)
{
return strcmp(((struct PeopleInfo*)e1)->name,((struct PeopleInfo*)e2)->name);
}
void SortContact(struct Contact* con)
{
qsort(con->data, con->sz, sizeof(con->data[0]), cmp_by_name);
}
清空通讯录
同样使用memset库函数清空所有联系人信息
void ClearContact(struct Contact* con)
{
//使用memset函数
memset(con->data,0,MAX*sizeof(struct PeopleInfo));
con->sz = 0;
}
完整代码:点这里
本章完。



