实现一个通讯录;
通讯录可以用来存储1000个人的信息,每个人的信息包括:姓名、性别、年龄、电话、住址
提供方法:
- 添加联系人信息
- 删除指定联系人信息
- 查找指定联系人信息
- 修改指定联系人信息
- 显示所有联系人信息
- 清空所有联系人
- 以名字排序所有联系人
目录
通讯录的创建
通讯录功能的实现
添加联系人信息
删除指定联系人信息
查找指定联系人信息
修改指定联系人信息
显示所有联系人信息
清空所有联系人
以名字排序所有联系人
以文件的形式保存(进阶)
实现效果
源码展示
通讯录的创建
首先我们知道通讯录中的信息不可能是单一的类型,他一定是多种数据类型整合而成的,因此需要创建一个结构体来存放通讯录信息:(为了能够方便更改某些信息, 可以把某些量设置为宏)
#define NAME_MAX 15//名字最大长度
#define SEX_MAX 8//性别最大长度
#define TELE_MAX 12//电话号码最大长度
#define ADDS_MAX 30//地址最大长度
struct Telephone
{
char name[NAME_MAX];
char sex[SEX_MAX];
int age;
char tele[TELE_MAX];
char adds[ADDS_MAX];
};
这样一个结构体就可以存放一个人的信息,而要存放1000个人的信息,可以再创建一个结构体用来存放这些结构体数据:
struct TeleInfo
{
struct Telephone* data;
int sz;//表示通讯录的容量
};
我们知道这样一个结构体类型占用的内存比较大,而假如我们仅需要存储10个人20个人的信息,这时创建一个容量1000的通讯录就造成了内存的大量浪费,因此我们可以将其改进,设置成动态增长的模式:
#define CAPACITY 3//通讯录初始容量
#define ADD_CAPACITY 2//每次扩容增加的容量大小
#define NAME_MAX 15//名字最大长度
#define SEX_MAX 8//性别最大长度
#define TELE_MAX 12//电话号码最大长度
#define ADDS_MAX 30//地址最大长度
struct Telephone
{
char name[NAME_MAX];
char sex[SEX_MAX];
int age;
char tele[TELE_MAX];
char adds[ADDS_MAX];
};
struct TeleInfo
{
struct Telephone* data;
int sz;
int capacity;
};
初始设置的结构体大小比较小,等到内存不够时再重新开辟空间,这样就可以避免空间的浪费。
而这时再将其初始化,就创建出一个空通讯录:
void Init_TeleInfo(struct TeleInfo* p)
{
assert(p);
p->data = (struct Telephone*)malloc(CAPACITY * sizeof(struct Telephone));
if (p->data == NULL)
{
perror("Init_TeleInfo()");
return;
}
p->sz = 0;
p->capacity = CAPACITY;
}
接着就可以根据要求设计内需了。
通讯录功能的实现
为了能够是的各部分功能都能实现,首先需要两个重要的函数:
1、保证容量功能(如果不够先进行增容)
这个判断函数不通过使用者直接调用,因此可以在函数前添加static:
static int check_TeleInfo(struct TeleInfo* p)
{
if (p->sz == p->capacity)
{
//扩容
struct Telephone* ptr = (struct Telephone*)realloc(p->data,
(p->capacity + ADD_CAPACITY) * sizeof(struct Telephone));
if (ptr == NULL)
{
perror("add_TeleInfo()");
return -1;
}
p->data = ptr;
p->capacity += ADD_CAPACITY;
return 1;
}
return 0;
}
这时通讯录的容量确保是充足的,因此可以进行录入信息。
2、搜索信息功能
对于删除、查找、修改等操作,都需要首先判断通讯录中是否存在该联系人才能进行后续相关操作。因此首先需要写一个查找函数(这个函数同上,不通过使用者直接调用,因此可以在函数前添加static):
static int seek_TeleInfo(struct TeleInfo* p)
{
assert(p);
char name[NAME_MAX] = { 0 };
printf("请输入联系人姓名:>");
scanf("%s", name);
int i = 0;
for (i = 0; i < p->sz; i++)
{
if (strcmp(p->data[i].name, name) == 0)
{
return i;
}
}
return -1;
}
有了这两个前置函数,就可以无障碍实现各部分功能,具体如下:
添加联系人信息
void add_TeleInfo(struct TeleInfo* p)
{
assert(p);
int flag = check_TeleInfo(p);
if (flag == 1)
printf("增容成功\n");
else if (flag == -1)
return;
printf("请输入名字:>");
scanf("%s", p->data[p->sz].name);
printf("请输入性别:>");
scanf("%s", p->data[p->sz].sex);
printf("请输入年龄:>");
scanf("%d", &(p->data[p->sz].age));
printf("请输入电话:>");
scanf("%s", p->data[p->sz].tele);
printf("请输入地址:>");
scanf("%s", p->data[p->sz].adds);
p->sz++;
printf("添加成功\n");
}
删除指定联系人信息
void del_TeleInfo(struct TeleInfo* p)
{
assert(p);
//判断联系人是否存在
int ret = seek_TeleInfo(p);
if (ret == -1)
{
printf("该联系人不存在\n");
return;
}
else
{
//该位置后面的所有信息前移一格
for (; ret < p->sz; ret++)
p->data[ret] = p->data[ret + 1];
p->sz--;
printf("删除成功\n");
}
}
查找指定联系人信息
void find_TeleInfo(struct TeleInfo* p)
{
assert(p);
int ret = seek_TeleInfo(p);
if (ret == -1)
return;
else
{
//这里主要保证上下内容位置统一
printf("%-10s\t%-10s\t%-10s\t%-10s\t%-20s\n", "姓名", "性别", "年龄", "电话", "地址");
printf("%-10s\t%-10s\t%-10d\t%-10s\t%-20s\n", p->data[ret].name, p->data[ret].sex,
p->data[ret].age, p->data[ret].tele, p->data[ret].adds);
}
}
修改指定联系人信息
void modify_TeleInfo(struct TeleInfo* p)
{
assert(p);
//判断联系人是否存在
int ret = seek_TeleInfo(p);
if (ret == -1)
{
printf("该联系人不存在\n");
return;
}
printf("请输入名字:>");
scanf("%s", p->data[ret].name);
printf("请输入性别:>");
scanf("%s", p->data[ret].sex);
printf("请输入年龄:>");
scanf("%d", &(p->data[ret].age));
printf("请输入电话:>");
scanf("%s", p->data[ret].tele);
printf("请输入地址:>");
scanf("%s", p->data[ret].adds);
}
显示所有联系人信息
void show_TeleInfo(struct TeleInfo* p)
{
int i = 0;
printf("%-10s\t%-10s\t%-10s\t%-10s\t%-20s\n", "姓名", "性别", "年龄", "电话", "地址");
for (i = 0; i < p->sz; i++)
{
printf("%-10s\t%-10s\t%-10d\t%-10s\t%-20s\n", p->data[i].name, p->data[i].sex,
p->data[i].age, p->data[i].tele, p->data[i].adds);
}
}
清空所有联系人
void destroy_TeleInfo(struct TeleInfo* p)
{
free(p->data);
p->data = NULL;
p->sz = 0;
p->capacity = 0;
}
以名字排序所有联系人
int cmp_name(const struct Telephone* str1, const struct Telephone* str2)
{
return strcmp(str1->name, str2->name);
}
void sort_TeleInfo(struct TeleInfo* p)
{
qsort(p->data, p->sz, sizeof(struct Telephone), cmp_name);
}
以文件的形式保存(进阶)
这时通讯录的功能已经全部实现,不过我们发现这样的通讯录无法保存,即下次使用时并不能找到上次退出前存储的信息。要解决这个问题,其实将信息以文件的形式保存即可。
既然如此,我们就需要在打开时首先读取文件,而在结束退出后保存文件,那么只需添加两个函数,就可以达到保存信息的功能。
读取文件可以在初始化通讯录后进行:
void Init_TeleInfo(struct TeleInfo* p)
{
assert(p);
p->data = (struct Telephone*)malloc(CAPACITY * sizeof(struct Telephone));
if (p->data == NULL)
{
perror("Init_TeleInfo()");
return;
}
p->sz = 0;
p->capacity = CAPACITY;
load_TeleInfo(p);//仅多一次函数调用
}
读取文件内容函数:
void load_TeleInfo(struct TeleInfo* p)
{
//打开文件
FILE* pf = fopen("contact.txt", "rb");
if (pf == NULL)
{
perror("load_TeleInfo:fopen()");
return;
}
//读取文件内容并存储在结构体中
struct Telephone tmp = { 0 };
while (fread(&tmp, sizeof(struct Telephone), 1, pf))
{
check_TeleInfo(p);
p->data[p->sz] = tmp;
p->sz++;
}
//关闭文件
fclose(pf);
pf = NULL;
}
通讯录保存可以在退出前进行:
void save_TeleInfo(struct TeleInfo* p)
{
//打开文件
FILE* pf = fopen("contact.txt", "wb");
if (pf == NULL)
{
perror("save_TeleInfo:fopen");
return;
}
//写文件
int i = 0;
while (i < p->sz)
{
fwrite(p->data + i, sizeof(struct Telephone), 1, pf);
i++;
}
//关闭文件
fclose(pf);
pf = NULL;
}
实现效果
源码展示
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<assert.h>
#define CAPACITY 3//通讯录容量
#define ADD_CAPACITY 2//每次扩容增加的容量大小
#define NAME_MAX 15//名字最大长度
#define SEX_MAX 8//性别最大长度
#define TELE_MAX 12//电话号码最大长度
#define ADDS_MAX 30//地址最大长度
struct Telephone
{
char name[NAME_MAX];
char sex[SEX_MAX];
int age;
char tele[TELE_MAX];
char adds[ADDS_MAX];
};
struct TeleInfo
{
struct Telephone* data;
int sz;
int capacity;
};
//初始化通讯录
void Init_TeleInfo(struct TeleInfo* p);
//保存通讯录
void save_TeleInfo(struct TeleInfo* pc);
//销毁通讯录
void destroy_TeleInfo(struct TeleInfo* p);
//添加联系人
void add_TeleInfo(struct TeleInfo* p);
//删除指定联系人
void del_TeleInfo(struct TeleInfo* p);
//查找指定联系人
void find_TeleInfo(struct TeleInfo* p);
//修改指定联系人
void modify_TeleInfo(struct TeleInfo* p);
//展示通讯录所有联系人
void show_TeleInfo(struct TeleInfo* p);
//将通讯录按名字排序
void sort_TeleInfo(struct TeleInfo* p);
#include"contact2.h"
static int check_TeleInfo(struct TeleInfo* p)
{
if (p->sz == p->capacity)
{
//扩容
struct Telephone* ptr = (struct Telephone*)realloc(p->data,
(p->capacity + ADD_CAPACITY) * sizeof(struct Telephone));
if (ptr == NULL)
{
perror("add_TeleInfo()");
return -1;
}
p->data = ptr;
p->capacity += ADD_CAPACITY;
return 1;
}
return 0;
}
void load_TeleInfo(struct TeleInfo* p)
{
//打开文件
FILE* pf = fopen("contact.txt", "rb");
if (pf == NULL)
{
perror("load_TeleInfo:fopen()");
return;
}
//读取文件
struct Telephone tmp = { 0 };
while (fread(&tmp, sizeof(struct Telephone), 1, pf))
{
check_TeleInfo(p);
p->data[p->sz] = tmp;
p->sz++;
}
//关闭文件
fclose(pf);
pf = NULL;
}
void Init_TeleInfo(struct TeleInfo* p)
{
assert(p);
p->data = (struct Telephone*)malloc(CAPACITY * sizeof(struct Telephone));
if (p->data == NULL)
{
perror("Init_TeleInfo()");
return;
}
p->sz = 0;
p->capacity = CAPACITY;
load_TeleInfo(p);
}
void add_TeleInfo(struct TeleInfo* p)
{
assert(p);
int flag = check_TeleInfo(p);
if (flag == 1)
printf("增容成功\n");
else if (flag == -1)
return;
printf("请输入名字:>");
scanf("%s", p->data[p->sz].name);
printf("请输入性别:>");
scanf("%s", p->data[p->sz].sex);
printf("请输入年龄:>");
scanf("%d", &(p->data[p->sz].age));
printf("请输入电话:>");
scanf("%s", p->data[p->sz].tele);
printf("请输入地址:>");
scanf("%s", p->data[p->sz].adds);
p->sz++;
printf("添加成功\n");
}
static int seek_TeleInfo(struct TeleInfo* p)
{
assert(p);
char name[NAME_MAX] = { 0 };
printf("请输入联系人姓名:>");
scanf("%s", name);
int i = 0;
for (i = 0; i < p->sz; i++)
{
if (strcmp(p->data[i].name, name) == 0)
{
return i;
}
}
return -1;
}
void find_TeleInfo(struct TeleInfo* p)
{
assert(p);
int ret = seek_TeleInfo(p);
if (ret == -1)
{
printf("该联系人不存在\n");
return;
}
else
{
printf("%-10s\t%-10s\t%-10s\t%-10s\t%-20s\n", "姓名", "性别", "年龄", "电话", "地址");
printf("%-10s\t%-10s\t%-10d\t%-10s\t%-20s\n", p->data[ret].name, p->data[ret].sex,
p->data[ret].age, p->data[ret].tele, p->data[ret].adds);
}
}
void del_TeleInfo(struct TeleInfo* p)
{
assert(p);
//判断联系人是否存在
int ret = seek_TeleInfo(p);
if (ret == -1)
{
printf("该联系人不存在\n");
return;
}
else
{
for (; ret < p->sz; ret++)
p->data[ret] = p->data[ret + 1];
p->sz--;
printf("删除成功\n");
}
}
void modify_TeleInfo(struct TeleInfo* p)
{
assert(p);
//判断联系人是否存在
int ret = seek_TeleInfo(p);
if (ret == -1)
{
printf("该联系人不存在\n");
return;
}
printf("请输入名字:>");
scanf("%s", p->data[ret].name);
printf("请输入性别:>");
scanf("%s", p->data[ret].sex);
printf("请输入年龄:>");
scanf("%d", &(p->data[ret].age));
printf("请输入电话:>");
scanf("%s", p->data[ret].tele);
printf("请输入地址:>");
scanf("%s", p->data[ret].adds);
}
void show_TeleInfo(struct TeleInfo* p)
{
int i = 0;
printf("%-10s\t%-10s\t%-10s\t%-10s\t%-20s\n", "姓名", "性别", "年龄", "电话", "地址");
for (i = 0; i < p->sz; i++)
{
printf("%-10s\t%-10s\t%-10d\t%-10s\t%-20s\n", p->data[i].name, p->data[i].sex,
p->data[i].age, p->data[i].tele, p->data[i].adds);
}
}
int cmp_name(const struct Telephone* str1, const struct Telephone* str2)
{
return strcmp(str1->name, str2->name);
}
void sort_TeleInfo(struct TeleInfo* p)
{
qsort(p->data, p->sz, sizeof(struct Telephone), cmp_name);
}
void save_TeleInfo(struct TeleInfo* p)
{
//打开文件
FILE* pf = fopen("contact.txt", "wb");
if (pf == NULL)
{
perror("save_TeleInfo:fopen");
return;
}
//写文件
int i = 0;
while (i < p->sz)
{
fwrite(p->data + i, sizeof(struct Telephone), 1, pf);
i++;
}
//关闭文件
fclose(pf);
pf = NULL;
}
void destroy_TeleInfo(struct TeleInfo* p)
{
free(p->data);
p->data = NULL;
p->sz = 0;
p->capacity = 0;
}
#include"contact2.h"
void menu()
{
printf("***********************\n");
printf("****1.add 2.delete***\n");
printf("****3.seek 4.modify***\n");
printf("****5.show 6.clear ***\n");
printf("****7.sort 0.exit ***\n");
printf("***********************\n");
}
enum choose
{
EXIT,
ADD,
DELETE,
SEEK,
MODIFY,
SHOW,
CLEAR,
SORT
};
int main()
{
int input;
struct TeleInfo con;
//初始化通讯录
Init_TeleInfo(&con);
do
{
menu();
printf("请选择你要进行的操作:>");
scanf("%d", &input);
switch (input)
{
case EXIT:
save_TeleInfo(&con);
printf("保存成功\n");
destroy_TeleInfo(&con);
printf("退出成功\n");
break;
case ADD:
add_TeleInfo(&con);
break;
case DELETE:
del_TeleInfo(&con);
break;
case SEEK:
find_TeleInfo(&con);
break;
case MODIFY:
modify_TeleInfo(&con);
break;
case SHOW:
show_TeleInfo(&con);
break;
case CLEAR:
destroy_TeleInfo(&con);
break;
case SORT:
sort_TeleInfo(&con);
break;
default:
break;
}
} while (input);
return 0;
}