这次我们来实现一个简单的通讯录
目录
既然是通讯录,我们要实现以下内容
1.我们要储存的是人的信息,我们要有人的姓名,年龄,性别,地址,电话等等
2.我们的通讯录要能储存很多人的信息,比如100个
3.通讯录的功能:增加联系人,删除联系人,查找联系人,修改联系人信息,显示所有联系人,还可以写一个排序功能(按年龄,名字排序等等)
我们还是使用工程化的写法来完成
1.基本框架及菜单的实现
我们先来实现基本框架,我们先要有一个菜单,来显示我们的功能
void menu() {
printf("*****************************\n");
printf("*****1. 新建联系人 ******\n");
printf("*****2. 删除联系人 ******\n");
printf("*****3. 查找联系人 ******\n");
printf("*****4. 修改联系人信息 ******\n");
printf("*****5. 联系人列表 ******\n");
printf("*****6. 联系人列表排序 ******\n");
printf("*****0. 退出通讯录 ******\n");
printf("*****************************\n");
}
int main() {
int input=0;
do {
menu();
printf("请选择:>");
scanf("%d", &input);
switch (input) {
case 1:
break;
case 2:
break;
case 3:
break;
case 4:
break;
case 5:
break;
case 6:
break;
case 0:
printf("退出通讯录!\n");
break;
default:
printf("选择错误!请重新选择!\n");
break;
}
} while (input);
}
并且我们启动通讯录后要每次都能打印出功能列表,我们使用do-while语句来完成,并且使用switch来完成我们的框架,菜单按照自己的喜好进行打印即可
2.相关结构体的实现
typedef struct PeoInfo {
char name[20];//名字
int age;//年龄
char sex[5];//性别
char addr[30];//住址
char tele[12];//电话
}PeoInfo;
typedef struct Contact {
PeoInfo data[100];//存放人的信息
int sz;//当前存放信息数量
}Contact;
我们先创建人的信息结构体PeoInfo,接着因为我们要存放100个人信息,我们创建通讯录的结构体Contact,接着我们就可以创建通讯录了,有了通讯录后,我们需要对他进行初始化,所以我们在.h文件里对其进行声明,在.c文件里实现
3.通讯录的初始化
void InitContact(Contact* pc){//初始化通讯录
assert(pc);
pc->sz = 0;
memset(pc->data, 0,sizeof(pc->data));
}
我们将sz先置为0,再使用memset函数对其进行填充,因为我们传的是结构体的地址,我们通过地址找到结构体的数组,此时我们用sizeof计算出的就是整个数组的大小,我们将这块空间初始化为0
4.新建联系人
在完成新建联系人前,我们先将我们的代码的通用性提高,使用#define来完成
#define MAX 100//最大联系人数量
#define NAME_MAX 20//最大名字字符数
#define SEX_MAX 5//最大性别字符数
#define ADDR_MAX 30//最大住址字符数
#define TELE_MAX 12//最大电话字符数
typedef struct PeoInfo {
char name[NAME_MAX];//名字
int age;//年龄
char sex[SEX_MAX];//性别
char addr[ADDR_MAX];//住址
char tele[TELE_MAX];//电话
}PeoInfo;
typedef struct Contact {
PeoInfo data[MAX];//存放人的信息
int sz;//当前存放信息数量
}Contact;
这样修改可以大大增加代码的可维护性,比如我们未来想要让通讯录里可以有200个联系人,只需修改MAX的值为200即可
//新建联系人
void AddContact(Contact* pc) {
assert(pc);
if (pc->sz == MAX) {
printf("通讯录已满,无法添加!\n");
return;
}
//添加一个联系人
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].addr);
printf("请输入电话:>");
scanf("%s", pc->data[pc->sz].tele);
pc->sz++;
}
接着就是我们的新建联系人了,我们首先要判断通讯录是否已满,已满的话我们输出信息,并退出,接着就是添加联系人,因为除了年龄外其他都是数组,数组名就是地址,所以不需要取地址,而年龄作为整数是需要取地址的,最后别忘了让sz++
5.显示所有联系人信息
当我们新建一个联系人后,我们想要对程序进行检测,就需要打印出我们的数据,所以我们先完成显示联系人的信息
//显示通讯录中所有联系人信息
void ShowContact(const Contact* pc) {
assert(pc);
int i = 0;
printf("%-20s\t%-4s\t%-5s\t%-20s\t%-12s\n","姓名","年龄","性别","住址","电话号码");
for (i = 0; i < pc->sz; i++) {
printf("%-20s\t%-4d\t%-5s\t%-20s\t%-12s\n",pc->data[i].name,
pc->data[i].age,
pc->data[i].sex,
pc->data[i].addr,
pc->data[i].tele);
}
}
我们使用左对齐来保证美观,使用for循环打印即可,并且因为是打印,我们不会修改信息,所以可以加上const,我们来测试一下
6.删除联系人
我们的删除联系人可以通过输入一个名字,然后删除该联系人信息
我们的删除方法有两种,一种是将后续数组的联系人全部往前挪动一位,然后使sz-1,第二种是可以让最后一位联系人直接覆盖当前联系人的位置,然后sz-1,第一种不会打乱顺序,但是效率低,第二种效率高,但是会打乱顺序,大家自行判断选择即可,我这里选择第一种
//删除联系人
void DelContact(Contact* pc) {
assert(pc);
char name[NAME_MAX] = { 0 };
if (pc->sz == 0) {
printf("通讯录为空!无法删除!\n");
return;
}
//查找需要删除的人
printf("请输入需要删除联系人的姓名:>");
scanf("%s", name);
int i = 0;
int del = 0;
for (i = 0; i < pc->sz; i++) {
if(strcmp(pc->data[i].name, name) == 0) {
del = i;
break;
}
}
//删除
for (i = del; i < pc->sz - 1; i++) {
pc->data[i] = pc->data[i + 1];
}
pc->sz--;
printf("删除联系人成功!\n");
}
我们先要判断通讯录是否为空,不为空我们才能进行删除操作,接着我们通过strcmp进行依次比较,找到需要删除的联系人的下标,然后将后续联系人往前移动,移动时要注意,我们的终止条件是i<pc->sz-1,这样我们可以把最后一位联系人也往前移动一位,此时数组里有两个最后一位联系人,但我们只需将sz-1即可让数组无法访问到多出来的最后一位
我们发现我们后续要实现的查找和修改,还有我们已经实现的删除,都需要对数组进行查找,我们可以查找封装成一个函数多次使用,提高代码的复用性
//根据名字查找
FindByName(const 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[NAME_MAX] = { 0 };
if (pc->sz == 0) {
printf("通讯录为空!无法删除!\n");
return;
}
//查找需要删除的人
printf("请输入需要删除联系人的姓名:>");
scanf("%s", name);
int ret = FindByName(pc, name);
if (ret == -1) {
printf("该联系人不存在!\n");
return;
}
//删除
int i = 0;
for (i = ret; i < pc->sz - 1; i++) {
pc->data[i] = pc->data[i + 1];
}
pc->sz--;
printf("删除联系人成功!\n");
}
7.查找指定联系人
//查找联系人
void SearchContact(const Contact* pc) {
assert(pc);
char name[NAME_MAX] = { 0 };
printf("请输入要查找的联系人的姓名:>");
scanf("%s", name);
int pos = FindByName(pc, name);
if (pos == -1) {
printf("该联系人不存在!\n");
return;
}
printf("%-20s\t%-4s\t%-5s\t%-20s\t%-12s\n", "姓名", "年龄", "性别", "住址", "电话号码");
printf("%-20s\t%-4d\t%-5s\t%-20s\t%-12s\n", pc->data[pos].name,
pc->data[pos].age,
pc->data[pos].sex,
pc->data[pos].addr,
pc->data[pos].tele);
}
我们使用刚才封装的查找函数即可,找到之后将他打印出来
8.修改联系人信息
//修改联系人信息
void ModifyContact(Contact* pc) {
assert(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("%d", &(pc->data[pos].age));
printf("请输入性别:>");
scanf("%s", pc->data[pos].sex);
printf("请输入住址:>");
scanf("%s", pc->data[pos].addr);
printf("请输入电话:>");
scanf("%s", pc->data[pos].tele);
printf("修改成功!\n");
}
修改也是先查找,再修改,使用我们之前的代码即可拼接而成,修改信息就是再录入一遍该联系人
9.对联系人进行排序
对通讯录排序可以通过对年龄排序,也可以通过名字的字典序来进行排序,我这里选择名字排序,大家可以根据需要进行添加多种排序方法
int cmp_name(const void* e1, const void* e2) {
return strcmp(((PeoInfo*)e1)->name, ((PeoInfo*)e2)->name);
}
//通讯录排序
void SortContact(Contact* pc) {
assert(pc);
qsort(pc, pc->sz, sizeof(pc->data[0]),cmp_name);
printf("已将通讯录按名字进行排序!\n");
}
我们使用qsort即可完成,不知道如何使用该函数的可以参考我的往前文章,在回调函数里我详细介绍了该函数
到这里,我们的简单通讯录就已经完成,后续我们可以文件操作系统来对其进行扩展,最后我会附上全部代码
10.完整代码
#pragma once
//Contact.h
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<assert.h>
#define MAX 100//最大联系人数量
#define NAME_MAX 20//最大名字字符数
#define SEX_MAX 5//最大性别字符数
#define ADDR_MAX 30//最大住址字符数
#define TELE_MAX 12//最大电话字符数
typedef struct PeoInfo {
char name[NAME_MAX];//名字
int age;//年龄
char sex[SEX_MAX];//性别
char addr[ADDR_MAX];//住址
char tele[TELE_MAX];//电话
}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 SearchContact(const Contact* pc);
//修改联系人信息
void ModifyContact(Contact* pc);
//通讯录排序
void SortContact(Contact* pc);
#include"Contact.h"
//Contact.c
//初始化通讯录
void InitContact(Contact* pc){
assert(pc);
pc->sz = 0;
memset(pc->data, 0,sizeof(pc->data));
}
//新建联系人
void AddContact(Contact* pc) {
assert(pc);
if (pc->sz == MAX) {
printf("通讯录已满,无法添加!\n");
return;
}
//添加一个联系人
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].addr);
printf("请输入电话:>");
scanf("%s", pc->data[pc->sz].tele);
pc->sz++;
}
//显示通讯录中所有联系人信息
void ShowContact(const Contact* pc) {
assert(pc);
int i = 0;
printf("%-20s\t%-4s\t%-5s\t%-20s\t%-12s\n","姓名","年龄","性别","住址","电话号码");
for (i = 0; i < pc->sz; i++) {
printf("%-20s\t%-4d\t%-5s\t%-20s\t%-12s\n",pc->data[i].name,
pc->data[i].age,
pc->data[i].sex,
pc->data[i].addr,
pc->data[i].tele);
}
}
//根据名字查找
FindByName(const 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[NAME_MAX] = { 0 };
if (pc->sz == 0) {
printf("通讯录为空!无法删除!\n");
return;
}
//查找需要删除的人
printf("请输入需要删除联系人的姓名:>");
scanf("%s", name);
int ret = FindByName(pc, name);
if (ret == -1) {
printf("该联系人不存在!\n");
return;
}
//删除
int i = 0;
for (i = ret; i < pc->sz - 1; i++) {
pc->data[i] = pc->data[i + 1];
}
pc->sz--;
printf("删除联系人成功!\n");
}
//查找联系人
void SearchContact(const Contact* pc) {
assert(pc);
char name[NAME_MAX] = { 0 };
printf("请输入要查找的联系人的姓名:>");
scanf("%s", name);
int pos = FindByName(pc, name);
if (pos == -1) {
printf("该联系人不存在!\n");
return;
}
printf("%-20s\t%-4s\t%-5s\t%-20s\t%-12s\n", "姓名", "年龄", "性别", "住址", "电话号码");
printf("%-20s\t%-4d\t%-5s\t%-20s\t%-12s\n", pc->data[pos].name,
pc->data[pos].age,
pc->data[pos].sex,
pc->data[pos].addr,
pc->data[pos].tele);
}
//修改联系人信息
void ModifyContact(Contact* pc) {
assert(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("%d", &(pc->data[pos].age));
printf("请输入性别:>");
scanf("%s", pc->data[pos].sex);
printf("请输入住址:>");
scanf("%s", pc->data[pos].addr);
printf("请输入电话:>");
scanf("%s", pc->data[pos].tele);
printf("修改成功!\n");
}
int cmp_name(const void* e1, const void* e2) {
return strcmp(((PeoInfo*)e1)->name, ((PeoInfo*)e2)->name);
}
//通讯录排序
void SortContact(Contact* pc) {
assert(pc);
qsort(pc, pc->sz, sizeof(pc->data[0]),cmp_name);
printf("已将通讯录按名字进行排序!\n");
}
#include"Contact.h"
//test.c
void menu() {
printf("*****************************\n");
printf("*****1. 新建联系人 ******\n");
printf("*****2. 删除联系人 ******\n");
printf("*****3. 查找联系人 ******\n");
printf("*****4. 修改联系人信息 ******\n");
printf("*****5. 联系人列表 ******\n");
printf("*****6. 联系人列表排序 ******\n");
printf("*****0. 退出通讯录 ******\n");
printf("*****************************\n");
}
int main() {
int input=0;
//创建通讯录
Contact con;
//初始化通讯录
InitContact(&con);
do {
menu();
printf("请选择:>");
scanf("%d", &input);
switch (input) {
case 1:
AddContact(&con);
break;
case 2:
DelContact(&con);
break;
case 3:
SearchContact(&con);
break;
case 4:
ModifyContact(&con);
break;
case 5:
ShowContact(&con);
break;
case 6:
SortContact(&con);
break;
case 0:
printf("退出通讯录!\n");
break;
default:
printf("选择错误!请重新选择!\n");
break;
}
} while (input);
}
希望大家可以有所收获
如有错误,还请指正