一、如何设计一个通讯录
1.设计思路
思路:我们手机上的通讯录可以实现排序,查找,删除,修改,显示以及添加联系人的功能,而通讯录的实现则需要我们的结构体来对我们的联系人进行一个分装,储存的联系人我们可以知道TA的名,TA的年龄,TA的地址,TA的电话号码以及联系人的性别,这些我们都可以采用结构体的方式对联系人进行存储。因此我们先创建一个含有名字,性别,电话,住址,年龄的结构体,设计一个菜单选择通讯录的功能,再根据选择的功能,写分装函数实现。
2.实现步骤
(1)创建通讯录,并将它初始化
(2)写功能菜单,用do_while循环/使用枚举依次列出功能
(3)在每个case语句中分装通讯录功能并单独写函数实行
3.需要涉及的C语言知识
(1)do_while循环的使用
(2)枚举的使用
(3)宏定义
(4)switch与case语句
(5)qsort函数的使用
二、创建头文件与源文件
我们在开始写通讯录之前创建两个源文件,分别命名为contact.c,test.c,contact.c用来写我们的通讯录功能,而test.c文件则帮助我们测试通讯录的运行。函数的创建以及结构体都需要声明,因此我们再创建一个头文件命名为contact.h。
1.头文件的声明
我们在头文件中创建我们的结构体以及我们的函数声明,那么我们就依步创建我们的通讯录吧,首先创建我们的结构体
//类型的声明
typedef struct PeoInfo
{
char name[MAX_NAME];
int age;
char sex[MAX_SEX];
char tele[MAX_TELE];
char addr[MAX_ADDR];
}PeoInfo;
2.主函数的创立
创立一个通讯录并将他初始化,如下:
int main()
{
test();
return 0;
}
void test()
{
//得有一个通序录
Contact con;
//初始化通讯录
InitContact(&con);
初始化通讯录
typedef struct Contact
{
PeoInfo data[MAX];
int sz;
}Contact;
//通讯录的初始
void InitContact(Contact* pc)
{
assert(pc);
memset(pc->data, 0, sizeof(pc->data));
pc->sz = 0;
}
memset的作用就是初始化通讯录,我们想每当录入一个联系人,我们的通讯录就可以统计一下当前通讯录中存在了多少位联系人,因此,我们创建了contact结构体来创建一个联系人的数组,用sz来统计联系人的个数,为了避免我们在后面想更改通讯录大小,我们可以使用宏的定义去避免我们后面满代码的去寻找数据修改,所以我们把PeoInfo成员所分配的内存用宏表示,我们只需要在头文件中定义
#define MAX 100
#define MAX_NAME 20
#define MAX_SEX 5
#define MAX_TELE 12
#define MAX_ADDR 30
接下来,我们建立一个菜单,我们可以但是创建一个名为菜单的函数去实现菜单的打印,如下:
void menu()
{
printf("******************************\n");
printf("******** 1.add 2.del******\n");
printf("******** 3.search 4.modify***\n");
printf("******** 5.show 6.sort*****\n");
printf("******** 0.exit ******\n");
}
再创建一个变量input,用input来进行功能选择,那如何实现这个菜单选择的功能呢??这里当然就是使用我们的switch语句和case语句的知识了。
int input = 0;
printf("请选择:\n");
scanf("%d", &input);
switch (input)
{
case ADD:
AddContact(&con);
break;
case DEL:
DelContact(&con);
break;
case SEARCH:
Search_Contact(&con);
break;
case MODIFY:
Modify_Contact(&con);
break;
case SHOW:
ShowContact(&con);
break;
case SORT:
Sort_Contact(&con);
break;
case EXIT:
break;
}
} while (input);
正常来说,我们的case语句后面写成 阿拉伯数字,不过我们为了提高代码的可读性,于是采用了枚举,提高了代码的可读性,让代码更加易懂。
case 1:
AddContact(&con);
break;
case 2:
DelContact(&con);
break;
case 3:
Search_Contact(&con);
break;
case 4:
Modify_Contact(&con);
enum OPTION //提高代码可读性
{
EXIT,
ADD,
DEL,
SEARCH,
MODIFY,
SHOW,
SORT
};
菜单打印完后,我们就依次去完善通讯录的功能。
三、通讯录功能完善
1.添加联系人
实现增加联系人的功能,创建一个AddContact的函数实现增加联系人的功能,同时每增加一个联系人,我们的sz需要++,统计当前联系人。当然在用函数实现功能时,我们都需要对函数进行声明,而声明都需要在头文件中进行。
//增加联系人信息
void AddContact(Contact* pc);
添加联系人不就是输入联系人信息嘛?所以我们利用输入函数,把我们所需要的录入的信息输入进去就好了,每次成功添加联系人我们都需要带动我们的sz++,统计联系人个数,在添加完联系人之后,提醒用户添加成功,代码如下:
printf("请输入名字:");
scanf("%s", pc->data[pc->sz].name);
printf("请输入年龄: ");
scanf("%d", &(pc->data[pc->sz].age));
printf("请输入性别:");
scanf("%s", pc->data[pc->sz].sex);
printf("请输入电话: ");
scanf("%s", pc->data[pc->sz].tele);
printf("请输入住址:");
scanf("%s", pc->data[pc->sz].addr);
pc->sz++;
printf("成功添加联系人\n");
你以为就这样美美的结束了?再仔细想一想,如果我们的通讯录内存满了怎么办?联系人还能顺利添加嘛?因此我们在正式添加联系人之前判断一下通讯录是否已满,如果通讯录满了,那我们就不在继续往下添加联系人了,顺便提醒我们的用户通讯录已满,添加失败。
if (pc->sz == MAX)
{
printf("通讯录已满,添加失败\n");
return;
}
2.删除联系人
用户输入想删除的联系人,找到目标联系人,把目标联系人后面的联系人位置向前移动,覆盖掉目标联系人的信息,这就算是删除完毕了,当覆盖完之后,我们需要提醒用户,删除成功。当然了,不是到这里就结束了,我们还需要考虑用户所删除的联系人是否存在,若所需删除的联系人不存在,我们需要提醒用户该联系人不存在。当然了,每一个实现功能的函数我们都需要对此进行声明。
//删除联系人信息
void DelContact(Contact* pc);
//删除联系人
void DelContact(Contact* pc)
{
assert(pc);
char name[MAX_NAME] = { 0 };
printf("请输入要删除的联系人\n");
scanf("%s", name);
if (pc->sz == 0)
{
printf("未添加联系人,无法删除\n");
return;
}
//寻找要删除的人
int del = FindByName(pc,name);
if (del == -1)
{
printf("该联系人不存在,无法删除\n");
return;
}
//删除人的坐标
for (int i = del; i < pc->sz-1; i++)
{
pc->data[i] = pc->data[i + 1];
}
pc->sz--;
printf("成功删除联系人\n");
}
我们这里查找联系人单独写成了一个函数,因为考虑到后面查找联系人这个功能我们会经常使用,为了减少不必要的工作量,我们于是单独写了一个函数去实现这个功能。
int FindByName(Contact* pc, char name[])
{
int i = 0;
for (i = 0; i < pc->sz; i++)
{
if (strcmp(pc->data[i].name, name)==0)
{
return i;
}
}
return-1;
}
3.查找联系人
简单来讲这个功能就是寻找目标坐标,并将其打印的题目类似,还是写一个实现这个功能的函数,并且还要思考如果查找的目标不存在,则需要提醒用户查找对象不存在。代码:
void Search_Contact(const Contact* pc)
{
assert(pc);
char name[MAX_NAME] = { 0 };
printf("请输入需要查找的联系人\n");
scanf("%s", name);
/*int flag = 0;
for (int i = 0; i < pc->sz; i++)
{
if (strcmp(pc->data[i].name, name) == 0)
{
printf("%20s\t%4d\t%5s\t%12s\t%30s\n", pc->data[i].name, pc->data[i].age,
pc->data[i].sex, pc->data[i].tele, pc->data[i].addr);
flag = 1;
}
}
if (flag == 0)
{
printf("该联系人不存在\n");
return 0;
}*/
int ret = FindByName(pc, name);
if (ret == -1)
{
printf("该联系人不存在\n");
}
else
{
printf("%20s\t%4d\t%5s\t%12s\t%30s\n", pc->data[ret].name, pc->data[ret].age,
pc->data[ret].sex, pc->data[ret].tele, pc->data[ret].addr);
}
}
4.修改联系人
首先我们需要先找到我们的目标联系人,锁定目标联系人,重新录入信息,代码参考联系人的添加,这时候就有朋友想我这联系人的信息就个别错误,想单独修改某个信息怎么办?那也简单,我们还是利用switch语句,建立一个修改联系人信息的菜单,确定用户要修改联系人的什么信息,再根据选择的要求进行实现,还是上代码来看看如何实现的吧。
(1)联系人查找:
char name[30] = { 0 };
printf("请输入需要修改的联系人:\n");
scanf("%s", name);
for (int i = 0; i < pc->sz; i++)
{
if (strcmp(pc->data[i].name, name) == 0)
(2)菜单打印:
printf("***** 可修改的内容 *****\n");
printf("****1.名字 2.年龄*******\n");
printf("****3.电话 4.地址*******\n");
printf("****5.性别 0.exit*******\n");
printf("请修改你需要修改的内容:\n");
(3)修改信息选择及提示用户修改成功:
int input = 0;
char sort[50] = { 0 };
int old = 0;
printf("***** 可修改的内容 *****\n");
printf("****1.名字 2.年龄*******\n");
printf("****3.电话 4.地址*******\n");
printf("****5.性别 0.exit*******\n");
printf("请修改你需要修改的内容:\n");
scanf("%d", &input);
switch (input)
{
case NAME:
printf("请修改:\n");
scanf("%s", sort);
strcpy(pc->data[i].name, sort);
printf("修改成功\n");
break;
case AGE:
printf("请修改:\n");
scanf("%d", &old);
pc->data[i].age = old;
printf("修改成功\n");
break;
case TELE:
printf("请修改:\n");
scanf("%s", sort);
strcpy(pc->data[i].tele, sort);
printf("修改成功\n");
break;
case ADDR:
printf("请修改:\n");
scanf("%s", sort);
strcpy(pc->data[i].addr, sort);
printf("修改成功\n");
break;
case SEX:
printf("请修改:\n");
scanf("%s", sort);
strcpy(pc->data[i].sex, sort);
printf("修改成功\n");
break;
case EXIT1:
break;
5.联系人显示:
展现联系人只不过就是重新打印已录入联系人的信息,代码如下:
void ShowContact(const Contact* pc)
{
assert(pc);
int i = 0;
//打印列标题
printf( "%-20s\t%-4s\t%-5s\t%-15s\t%-30s\n","名字","年龄","性别","电话","地址");
for (i = 0; i < pc->sz; i++)
{
printf("%-20s\t%-4d\t%-5s\t%-12s\t%-30s\n", pc->data[i].name, pc->data[i].age,
pc->data[i].sex, pc->data[i].tele, pc->data[i].addr);
}
}
6.排序联系人
联系人如何排序?是按照名字还是年龄?我们这里也可以使用switch语句进行选择,排序方式我们选择使用qsort函数进行排序。老规矩,还是来看看代码吧
//联系人排序
int com_name(const void* p1, const void* p2)
{
return strcmp(((PeoInfo*)p1)->name, ((PeoInfo*)p2)->name);
}
int com_age(const void* p1, const void* p2)
{
return (((PeoInfo*)p1)->age - ((PeoInfo*)p2)->age);
}
void Sort_Contact(Contact* pc)
{
int input = 0;
printf("****1.名字 2.年龄****\n");
printf("请选择你的排序方式:\n");
scanf("%d", &input);
int sz = sizeof(pc->data) / sizeof(pc->data[0]);
switch (input)
{
case 1:
qsort(pc->data,pc->sz, sizeof(PeoInfo), com_name);
break;
case 2:
qsort(pc->data, pc->sz, sizeof(PeoInfo), com_age);
break;
}
}
四、完整代码展示:
(1)头文件声明:
#include <string.h>
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#define MAX 100
#define MAX_NAME 20
#define MAX_SEX 5
#define MAX_TELE 12
#define MAX_ADDR 30
enum CHOOSE
{
EXIT1,
NAME,
AGE,
TELE,
ADDR,
SEX,
};
enum OPTION //提高代码可读性
{
EXIT,
ADD,
DEL,
SEARCH,
MODIFY,
SHOW,
SORT
};
//类型的声明
typedef struct PeoInfo
{
char name[MAX_NAME];
int age;
char sex[MAX_SEX];
char tele[MAX_TELE];
char addr[MAX_ADDR];
}PeoInfo;
//通讯录
typedef struct Contact
{
PeoInfo data[MAX];
int sz;
}Contact;
//函数声明
void InitContact(Contact* pc);
//增加联系人信息
void AddContact(Contact* pc);
//显示联系人信息
void ShowContact(const Contact* pc);
//删除联系人信息
void DelContact(Contact* pc);
//查找联系人
void Search_Contact(const Contact*pc);
//修改联系人
void Modify_Contact(Contact*pc);
//对联系人进行排序
void Sort_Contact(Contact*pc);
(2)函数实现——contact.c:
#define _CRT_SECURE_NO_WARNINGS 1
#pragma warning(disable:6031)
#include "contact.h"
#include <stdio.h>
//通讯录的初始
void InitContact(Contact* pc)
{
assert(pc);
memset(pc->data, 0, sizeof(pc->data));
pc->sz = 0;
}
void AddContact(Contact* pc)
{
assert(pc);
if (pc->sz == MAX)
{
printf("通讯录已满,添加失败\n");
return;
}
else
{
printf("请输入名字:");
scanf("%s", pc->data[pc->sz].name);
printf("请输入年龄: ");
scanf("%d", &(pc->data[pc->sz].age));
printf("请输入性别:");
scanf("%s", pc->data[pc->sz].sex);
printf("请输入电话: ");
scanf("%s", pc->data[pc->sz].tele);
printf("请输入住址:");
scanf("%s", pc->data[pc->sz].addr);
pc->sz++;
printf("成功添加联系人\n");
}
}
//显示联系人
void ShowContact(const Contact* pc)
{
assert(pc);
int i = 0;
//打印列标题
printf( "%-20s\t%-4s\t%-5s\t%-15s\t%-30s\n","名字","年龄","性别","电话","地址");
for (i = 0; i < pc->sz; i++)
{
printf("%-20s\t%-4d\t%-5s\t%-12s\t%-30s\n", pc->data[i].name, pc->data[i].age,
pc->data[i].sex, pc->data[i].tele, pc->data[i].addr);
}
}
//查找联系人
int FindByName(Contact* pc, char name[])
{
int i = 0;
for (i = 0; i < pc->sz; i++)
{
if (strcmp(pc->data[i].name, name)==0)
{
return i;
}
}
return-1;
}
//删除联系人
void DelContact(Contact* pc)
{
assert(pc);
char name[MAX_NAME] = { 0 };
printf("请输入要删除的联系人\n");
scanf("%s", name);
if (pc->sz == 0)
{
printf("未添加联系人,无法删除\n");
return;
}
//寻找要删除的人
int del = FindByName(pc,name);
if (del == -1)
{
printf("该联系人不存在,无法删除\n");
return;
}
//删除人的坐标
for (int i = del; i < pc->sz-1; i++)
{
pc->data[i] = pc->data[i + 1];
}
pc->sz--;
printf("成功删除联系人\n");
}
//查找联系人
void Search_Contact(const Contact* pc)
{
assert(pc);
char name[MAX_NAME] = { 0 };
printf("请输入需要查找的联系人\n");
scanf("%s", name);
/*int flag = 0;
for (int i = 0; i < pc->sz; i++)
{
if (strcmp(pc->data[i].name, name) == 0)
{
printf("%20s\t%4d\t%5s\t%12s\t%30s\n", pc->data[i].name, pc->data[i].age,
pc->data[i].sex, pc->data[i].tele, pc->data[i].addr);
flag = 1;
}
}
if (flag == 0)
{
printf("该联系人不存在\n");
return 0;
}*/
int ret = FindByName(pc, name);
if (ret == -1)
{
printf("该联系人不存在\n");
}
else
{
printf("%20s\t%4d\t%5s\t%12s\t%30s\n", pc->data[ret].name, pc->data[ret].age,
pc->data[ret].sex, pc->data[ret].tele, pc->data[ret].addr);
}
}
//修改联系人
void Modify_Contact(Contact* pc)
{
char name[30] = { 0 };
printf("请输入需要修改的联系人:\n");
scanf("%s", name);
for (int i = 0; i < pc->sz; i++)
{
if (strcmp(pc->data[i].name, name) == 0)
{
int input = 0;
char sort[50] = { 0 };
int old = 0;
printf("***** 可修改的内容 *****\n");
printf("****1.名字 2.年龄*******\n");
printf("****3.电话 4.地址*******\n");
printf("****5.性别 0.exit*******\n");
printf("请修改你需要修改的内容:\n");
scanf("%d", &input);
switch (input)
{
case NAME:
printf("请修改:\n");
scanf("%s", sort);
strcpy(pc->data[i].name, sort);
printf("修改成功\n");
break;
case AGE:
printf("请修改:\n");
scanf("%d", &old);
pc->data[i].age = old;
printf("修改成功\n");
break;
case TELE:
printf("请修改:\n");
scanf("%s", sort);
strcpy(pc->data[i].tele, sort);
printf("修改成功\n");
break;
case ADDR:
printf("请修改:\n");
scanf("%s", sort);
strcpy(pc->data[i].addr, sort);
printf("修改成功\n");
break;
case SEX:
printf("请修改:\n");
scanf("%s", sort);
strcpy(pc->data[i].sex, sort);
printf("修改成功\n");
break;
case EXIT1:
break;
}
}
}
}
//联系人排序
int com_name(const void* p1, const void* p2)
{
return strcmp(((PeoInfo*)p1)->name, ((PeoInfo*)p2)->name);
}
int com_age(const void* p1, const void* p2)
{
return (((PeoInfo*)p1)->age - ((PeoInfo*)p2)->age);
}
void Sort_Contact(Contact* pc)
{
int input = 0;
printf("****1.名字 2.年龄****\n");
printf("请选择你的排序方式:\n");
scanf("%d", &input);
int sz = sizeof(pc->data) / sizeof(pc->data[0]);
switch (input)
{
case 1:
qsort(pc->data,pc->sz, sizeof(PeoInfo), com_name);
break;
case 2:
qsort(pc->data, pc->sz, sizeof(PeoInfo), com_age);
break;
}
}
(3)通讯录测试——test.c
#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("******** 0.exit ******\n");
}
void test()
{
//得有一个通序录
Contact con;
//初始化通讯录
InitContact(&con);
int input = 0;
do
{
menu();
printf("请选择:\n");
scanf("%d", &input);
switch (input)
{
case ADD:
AddContact(&con);
break;
case DEL:
DelContact(&con);
break;
case SEARCH:
Search_Contact(&con);
break;
case MODIFY:
Modify_Contact(&con);
break;
case SHOW:
ShowContact(&con);
break;
case SORT:
Sort_Contact(&con);
break;
case EXIT:
break;
}
} while (input);
}
int main()
{
test();
return 0;
}
以上就是通讯录的完整写法,希望可以帮助各位老铁。文章有错误请评论区留言指出,感谢老铁的阅读。