通讯录
// 用宏替换后续经常出现的数字,便于程序的维护
#define NAME_MAX 20 // 名字的字符串的最大长度
#define SEX_MAX 20 // 性别的字符串的最大长度
#define TELE_MAX 20 // 电话的最大字符串的长度
#define ADDR_MAX 20 // 住址的最大字符串的长度
#define CON_INIT 3 // 通讯录的初识大小
// 定义每个人的信息为一个结构体,同时为了方便表示,采用typedef
typedef struct PeoInfo
{
char name[NAME_MAX]; // 每个人的姓名
char sex[SEX_MAX]; // 每个人的性别
int age; // 每个人的年龄
char tele[TELE_MAX]; // 每个人的电话
char addr[ADDR_MAX]; // 每个人的住址
}PeoInfo;
// 定义整个通讯录为一个结构体,同时为了方便表示,采用typedef
typedef struct Contact
{
// 为了节省空间,采用动态内存分配的方法来获取整个通讯录的空间
PeoInfo* data; // 结构体指针,可通过运算访问到所有人的信息
int size; // 表示当前通讯录存了多少人的信息
int capacity; // 表示该通讯录总共可以存多少人的信息
}Contact;
// 定义一个通讯录结构体
Contact con;
// 对该通讯录结构体进行初始化
// 此后应该传结构体的地址而不是结构体,原因是要对结构体作出修改
// 并且传结构体的地址节省空间且效率更高
InitContact(&con);
// 在这个函数内部对通讯录结构体进行初始化
void InitContact(Contact* pc)
{
// 此时通讯录是空的,应先为通讯录分配空间
pc->data = (PeoInfo*)malloc(sizeof(PeoInfo) * CON_INIT);
// 如果分配成功,将通讯录的size设为0,capacity设为初识大小
pc->size = 0;
pc->capacity = CON_INIT;
}
菜单如下:
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");
return;
}
用户的选择功能如下
// 定义input,用户输入input进行选择
int input;
do
{
menu(); // 打印菜单,提示用户进行选择
scanf("%d", &input); // 用户输入input进行选择
switch (input) // 用户选择后进入不同的功能
{
case ADD: // 增加联系人
AddContact(&con);
break;
case DEL: // 删除联系人
DeleteContact(&con);
break;
case SEARCH: // 查找联系人
SearchContact(&con);
break;
case MODIFY: // 改变联系人
ModifyContact(&con);
break;
case SORT: // 对联系人进行排序
SortContact(&con);
break;
case PRINT: // 打印所有联系人的信息
PrintContact(&con);
break;
case EXIT: // 退出程序并销毁
DestroyContact(&con);
break;
}
} while (input);
用枚举常量来表示各种选项
在每次增加联系人前,都要进行检查是否需要扩容的操作,若需要则进行扩容
void AddContact(Contact* pc)
{
// 判断通讯录是否已满,若满,进行扩容
if (pc->size == pc->capacity)
{
PeoInfo* tmp = (PeoInfo*)realloc(pc, sizeof(PeoInfo) * 2);
if (tmp == NULL)
{
printf("realloc fail\n");
return;
}
pc->data = tmp;
// 若扩容成功,增大capacity
pc->capacity *= 2;
}
// 输入要添加的联系人的信息
// 这里pc->data为结构体数组,pc->data[pc->size]为其中的元素,也就是某一个联系人的信息
printf("请输入名字\n");
scanf("%s", pc->data[pc->size].name);
printf("请输入性别\n");
scanf("%s", pc->data[pc->size].sex);
printf("请输入年龄\n");
scanf("%d", &pc->data[pc->size].age);
printf("请输入电话\n");
scanf("%s", pc->data[pc->size].tele);
printf("请输入住址\n");
scanf("%s", pc->data[pc->size].addr);
pc->size++; // 将存入的联系人的数量加1
// 添加成功后,向用户展示新的通讯录
PrintContact(pc);
}
void DeleteContact(Contact* pc)
{
printf("请输入要删除的联系人的名字\n");
char name[20];
scanf("%s", name);
// 定义一个新函数find,用来查找是否有这个联系人
// 如果有,返回联系人的下标,如果没有,返回-1
int ret = find(pc, name);
if (ret == -1)
{
printf("没有找到该联系人\n");
}
else
{
for (int i = ret; i < pc->size - 1; i++)
{
pc->data[i] = pc->data[i + 1];
}
pc->size--;
}
return;
}
这里还要定义一个find函数来找该联系人,如果找到返回该联系人的下标,如果找不到则返回-1。
int find(Contact* pc, char* name)
{
for (int i = 0; i < pc->size; i++)
{
if (strcmp(name, pc->data[i].name) == 0)
{
return i;
}
}
return -1;
}
查找时利用find函数来查找
void SearchContact(Contact* pc)
{
printf("请输入要查找的联系人的名字\n");
char name[20];
scanf("%s", name);
// 利用已经定义的find函数进行查找
int ret = find(pc, name);
if (ret == -1)
{
printf("没有找到该联系人\n");
}
else
{
// 如果找到,打印该联系人的信息,首先打印五个标题
printf("%-10s\t%-10s\t%-5s\t%-15s\t%-10s\n", "姓名", "性别", "年龄", "电话", "住址");
printf("%-10s\t%-10s\t%-5d\t%-15s\t%-10s\n",
pc->data[ret].name,
pc->data[ret].sex,
pc->data[ret].age,
pc->data[ret].tele,
pc->data[ret].addr);
}
return;
}
void ModifyContact(Contact* pc)
{
printf("请输入要修改的联系人的名字\n");
char name[20];
scanf("%s", name);
// 利用find函数进行查找
int ret = find(pc, name);
if (ret == -1)
{
printf("没有找到该联系人\n");
}
else
{
printf("请输入名字\n");
scanf("%s", pc->data[ret].name);
printf("请输入性别\n");
scanf("%s", pc->data[ret].sex);
printf("请输入年龄\n");
scanf("%d", &pc->data[ret].age);
printf("请输入电话\n");
scanf("%s", pc->data[ret].tele);
printf("请输入住址\n");
scanf("%s", pc->data[ret].addr);
}
return;
}
void SortContact(Contact* pc)
{
// 这里采用升序排列
// 且采用冒泡排序的方式进行排列
for (int i = 0; i < pc->size; i++)
{
for (int j = 0; j < pc->size - 1 - i; i++)
{
if (strcmp(pc->data[j].name, pc->data[j + 1].name) > 0)
{
char tmp[20];
strcpy(tmp, pc->data[j].name);
strcpy(pc->data[j].name, pc->data[j + 1].name);
strcpy(pc->data[j + 1].name, tmp);
}
}
}
printf("排序成功\n");
}
// 在这个函数内打印所有联系人的信息
void PrintContact(Contact* pc)
{
// 首先打印五个标题
printf("%-10s\t%-10s\t%-5s\t%-15s\t%-10s\n", "姓名", "性别", "年龄", "电话", "住址");
// 然后用for循环打印所有联系人的信息
for (int i = 0; i < pc->size; i++)
{
printf("%-10s\t%-10s\t%-5d\t%-15s\t%-10s\n",
pc->data[i].name,
pc->data[i].sex,
pc->data[i].age,
pc->data[i].tele,
pc->data[i].addr
);
}
}
void DestroyContact(Contact* pc)
{
free(pc->data);
pc->data = NULL;
pc->size = 0;
pc->capacity = 0;
}
利用文件实现
当通讯录退出的时候,把信息写到文件。
当通讯录初始化后,加载文件的信息到通讯录中。
在每次销毁通讯录之前将通讯录的信息保存到文件中
CheckCapacity函数中的内容直接拷贝AddContact函数中的数组扩容即可
#include
#include
#include
// 用宏替换后续经常出现的数字,便于程序的维护
#define NAME_MAX 20 // 名字的字符串的最大长度
#define SEX_MAX 20 // 性别的字符串的最大长度
#define TELE_MAX 20 // 电话的最大字符串的长度
#define ADDR_MAX 20 // 住址的最大字符串的长度
#define CON_INIT 3 // 通讯录的初识大小
// 定义每个人的信息为一个结构体,同时为了方便表示,采用typedef
typedef struct PeoInfo
{
char name[NAME_MAX]; // 每个人的姓名
char sex[SEX_MAX]; // 每个人的性别
int age; // 每个人的年龄
char tele[TELE_MAX]; // 每个人的电话
char addr[ADDR_MAX]; // 每个人的住址
}PeoInfo;
// 定义整个通讯录为一个结构体,同时为了方便表示,采用typedef
typedef struct Contact
{
// 为了节省空间,采用动态内存分配的方法来获取整个通讯录的空间
PeoInfo* data; // 结构体指针,可通过运算访问到所有人的信息
int size; // 表示当前通讯录存了多少人的信息
int capacity; // 表示该通讯录总共可以存多少人的信息
}Contact;
// 使用枚举常量来表示用户的各种选择
enum Option
{
EXIT,
ADD,
DEL,
SEARCH,
MODIFY,
SORT,
PRINT
};
void SaveContact(Contact* pc)
{
// 以读的形式打开文件
FILE* pf = fopen("contact.txt", "wb");
if (pf == NULL)
{
perror("fopen");
return;
}
// 将通讯录以二进制的形式保存到文件中
// 由于联系人的信息有很多,所以这里可以采用for循环
for (int i = 0; i < pc->size; i++)
{
fwrite(pc->data + i, sizeof(PeoInfo), 1, pf);
}
// 关闭文件
fclose(pf);
pf = NULL;
}
CheckCapacity(Contact* pc)
{
// 判断通讯录是否已满,若满,进行扩容
if (pc->size == pc->capacity)
{
PeoInfo* tmp = (PeoInfo*)realloc(pc, sizeof(PeoInfo) * 2);
if (tmp == NULL)
{
printf("realloc fail\n");
return;
}
pc->data = tmp;
// 若扩容成功,增大capacity
pc->capacity *= 2;
}
}
void LoadContact(Contact* pc)
{
// 以读的形式打开文件
FILE* pf = fopen("contact.txt", "rb");
if (pf == NULL)
{
perror("fopen");
return;
}
// 将文件中的内容加载到通讯录中
// 这里用fread函数,当fread函数读取的联系人信息数为0时,说明读取结束
PeoInfo tmp = { 0 }; // 定义一个联系人信息的结构体,便于读取
while (fread(&tmp, sizeof(PeoInfo), 1, pf))
{
CheckCapacity(pc); // 在这个函数中查看数组是否需要扩容,若需要,则扩容
pc->data[pc->size] = tmp;
pc->size++;
}
// 关闭文件
fclose(pf);
pf = NULL;
return;
}
// 在这个函数内部对通讯录结构体进行初始化
void InitContact(Contact* pc)
{
// 此时通讯录是空的,应先为通讯录分配空间
pc->data = (PeoInfo*)malloc(sizeof(PeoInfo) * CON_INIT);
// 如果分配成功,将通讯录的size设为0,capacity设为初识大小
pc->size = 0;
pc->capacity = CON_INIT;
LoadContact(pc);
return;
}
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");
return;
}
// 在这个函数内打印所有联系人的信息
void PrintContact(Contact* pc)
{
// 首先打印五个标题
printf("%-10s\t%-10s\t%-5s\t%-15s\t%-10s\n", "姓名", "性别", "年龄", "电话", "住址");
// 然后用for循环打印所有联系人的信息
for (int i = 0; i < pc->size; i++)
{
printf("%-10s\t%-10s\t%-5d\t%-15s\t%-10s\n",
pc->data[i].name,
pc->data[i].sex,
pc->data[i].age,
pc->data[i].tele,
pc->data[i].addr
);
}
}
void AddContact(Contact* pc)
{
CheckCapacity(pc);
// 输入要添加的联系人的信息
// 这里pc->data为结构体数组,pc->data[pc->size]为其中的元素,也就是某一个联系人的信息
printf("请输入名字\n");
scanf("%s", pc->data[pc->size].name);
printf("请输入性别\n");
scanf("%s", pc->data[pc->size].sex);
printf("请输入年龄\n");
scanf("%d", &pc->data[pc->size].age);
printf("请输入电话\n");
scanf("%s", pc->data[pc->size].tele);
printf("请输入住址\n");
scanf("%s", pc->data[pc->size].addr);
pc->size++; // 将存入的联系人的数量加1
// 添加成功后,向用户展示新的通讯录
PrintContact(pc);
}
int find(Contact* pc, char* name)
{
for (int i = 0; i < pc->size; i++)
{
if (strcmp(name, pc->data[i].name) == 0)
{
return i;
}
}
return -1;
}
void DeleteContact(Contact* pc)
{
printf("请输入要删除的联系人的名字\n");
char name[20];
scanf("%s", name);
// 定义一个新函数find,用来查找是否有这个联系人
// 如果有,返回联系人的下标,如果没有,返回-1
int ret = find(pc, name);
if (ret == -1)
{
printf("没有找到该联系人\n");
}
else
{
for (int i = ret; i < pc->size - 1; i++)
{
pc->data[i] = pc->data[i + 1];
}
pc->size--;
}
return;
}
void SearchContact(Contact* pc)
{
printf("请输入要查找的联系人的名字\n");
char name[20];
scanf("%s", name);
// 利用已经定义的find函数进行查找
int ret = find(pc, name);
if (ret == -1)
{
printf("没有找到该联系人\n");
}
else
{
// 如果找到,打印该联系人的信息,首先打印五个标题
printf("%-10s\t%-10s\t%-5s\t%-15s\t%-10s\n", "姓名", "性别", "年龄", "电话", "住址");
printf("%-10s\t%-10s\t%-5d\t%-15s\t%-10s\n",
pc->data[ret].name,
pc->data[ret].sex,
pc->data[ret].age,
pc->data[ret].tele,
pc->data[ret].addr);
}
return;
}
void ModifyContact(Contact* pc)
{
printf("请输入要修改的联系人的名字\n");
char name[20];
scanf("%s", name);
// 利用find函数进行查找
int ret = find(pc, name);
if (ret == -1)
{
printf("没有找到该联系人\n");
}
else
{
printf("请输入名字\n");
scanf("%s", pc->data[ret].name);
printf("请输入性别\n");
scanf("%s", pc->data[ret].sex);
printf("请输入年龄\n");
scanf("%d", &pc->data[ret].age);
printf("请输入电话\n");
scanf("%s", pc->data[ret].tele);
printf("请输入住址\n");
scanf("%s", pc->data[ret].addr);
}
return;
}
void SortContact(Contact* pc)
{
// 这里采用升序排列
// 且采用冒泡排序的方式进行排列
for (int i = 0; i < pc->size; i++)
{
for (int j = 0; j < pc->size - 1 - i; i++)
{
if (strcmp(pc->data[j].name, pc->data[j + 1].name) > 0)
{
char tmp[20];
strcpy(tmp, pc->data[j].name);
strcpy(pc->data[j].name, pc->data[j + 1].name);
strcpy(pc->data[j + 1].name, tmp);
}
}
}
printf("排序成功\n");
}
void DestroyContact(Contact* pc)
{
free(pc->data);
pc->data = NULL;
pc->size = 0;
pc->capacity = 0;
}
int main()
{
// 定义一个通讯录结构体
Contact con;
// 对该通讯录结构体进行初始化
// 此后应该传结构体的地址而不是结构体,原因是要对结构体作出修改
// 并且传结构体的地址节省空间且效率更高
InitContact(&con);
// 定义input,用户输入input进行选择
int input;
do
{
menu(); // 打印菜单,提示用户进行选择
scanf("%d", &input); // 用户输入input进行选择
switch (input) // 用户选择后进入不同的功能
{
case ADD: // 增加联系人
AddContact(&con);
break;
case DEL: // 删除联系人
DeleteContact(&con);
break;
case SEARCH: // 查找联系人
SearchContact(&con);
break;
case MODIFY: // 改变联系人
ModifyContact(&con);
break;
case SORT: // 对联系人进行排序
SortContact(&con);
break;
case PRINT: // 打印所有联系人的信息
PrintContact(&con);
break;
case EXIT: // 退出程序并销毁
//在销毁之前将通讯录内的信息保存到文件中
SaveContact(&con);
DestroyContact(&con);
break;
}
} while (input);
return 0;
}