目录
一,关于通讯录
二,通讯录功能实现
2.1 类型的定义
2.1.1 联系人类型声明
2.1.2 通讯录类型声明
2.2 添加联系人
2.2.1 静态版本
2.2.2 动态版本
2.3 删除联系人
2.4 查找联系人
2.5 修改联系人
2.6 显示联系人
2.7 清空联系人
2.8 排序联系人
2.8.1 以名字排序
2.8.2 以年龄排序
2.9 保存联系人
2.9.1 打开通讯录时从文件中读取数据
2.9.2 关系通讯录时将数据保存到文件中
三,完整代码
contact.h
Test.c
通讯录是对目前C语言使用的一次总体概括,通过实现通讯录,复习总结C语言的各种语法与知识,可以帮助我们更好地学习C语言。
#define MAX 100
#define MAX_NAME 20
#define MAX_SEX 5
#define MAX_TELE 12
#define MAX_ADDR 30
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; //指向了存放数据的空间
int sz; //记录的当前放的有效元素的个数
int capacity; //通讯录当前的最大容量
}Contact;
所谓静态版本,就是初始化通讯录的时候,指定通讯录大小,一旦联系人满了无法继续添加
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].tele);
printf("请输入地址:>");
scanf("%s", pc->data[pc->sz].addr);
pc->sz++;
printf("成功增加联系人\n");
}
所谓动态版本,就是通讯录的大小可以随着联系人的数量来定,多了就扩容,可以使空间更加有效地利用
先检查通讯录空间是否够用,不够用就扩容
int CheckCapacity(Contact* pc)
{
if (pc->sz == pc->capacity)
{
PeoInfo* ptr = (PeoInfo*)realloc(pc->data, (pc->capacity + INC_SZ) * sizeof(PeoInfo));
if (ptr == NULL)
{
perror("CheckCapacity");
return 0;
}
else
{
pc->data = ptr;
pc->capacity += INC_SZ;
printf("增容成功\n");
return 1;
}
}
return 1;
}
然后进行添加
void AddContact(Contact* pc)
{
assert(pc);
if (0 == CheckCapacity(pc))
{
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].tele);
printf("请输入地址:>");
scanf("%s", pc->data[pc->sz].addr);
pc->sz++;
printf("成功增加联系人\n");
}
要想删除联系人信息,得先找到用户输入地联系人信息在内存中地下标位置
找下标位置
static int 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)
{
if (pc->sz == 0)
{
printf("通讯录为空,无法删除\n");
return;
}
char name[MAX_NAME] = { 0 };
assert(pc);
//删除
printf("请输入要删除的人名字:>");
scanf("%s", name);
//找到要删除的人
int del = FindByName(pc, name);
if (del == -1)
{
printf("要删除的人不存在\n");
return;
}
int i = 0;
//删除坐标位del的联系人
for (i = del; 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[MAX_NAME] = { 0 };
printf("请输入要查找人的名字:>");
scanf("%s", name);
int pos = FindByName(pc, name);
if (pos == -1)
printf("要查找的人不存在\n");
else
{
printf("%-10s\t%-4s\t%-5s\t%-12s\t%-30s\n", "名字", "年龄", "性别", "电话", "地址");
//打印数据
printf("%-10s\t%-4d\t%-5s\t%-12s\t%-30s\n",
pc->data[pos].name,
pc->data[pos].age,
pc->data[pos].sex,
pc->data[pos].tele,
pc->data[pos].addr);
}
}
修改前也需要找到联系人哦
void ModifyContact(Contact* pc)
{
assert(pc);
char name[MAX_NAME] = { 0 };
printf("请输入要修改人的名字:>");
scanf("%s", name);
int pos = FindByName(pc, name);
if (pos == -1)
printf("要修改的人不存在\n");
else
{
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].tele);
printf("请输入地址:>");
scanf("%s", pc->data[pos].addr);
printf("修改成功\n");
}
}
void ShowContact(const Contact* pc)
{
assert(pc);
if (pc->sz == 0)
{
printf("当前通讯录暂无联系人数据\n");
return;
}
int i = 0;
//打印列标题
printf("%-10s\t%-4s\t%-5s\t%-12s\t%-30s\n", "名字", "年龄", "性别", "电话", "地址");
//打印数据
for (i = 0; i < pc->sz; i++)
{
printf("%-10s\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);
}
}
void DestroyContact(Contact* pc)
{
free(pc->data);
pc->data = NULL;
pc->capacity = 0;
pc->sz = 0;
}
以名字排序直接以首字母的ASCLL码来排序了
int cmp_name(const void* a, const void* b)
{
return strcmp((char*)a, (char*)b);
}
void SortContactName(Contact* pc)
{
assert(pc);
qsort(pc->data, pc->sz, sizeof(pc->data[0]), cmp_name);
printf("排序成功\n");
}
int cmp_age(const void* a,const void* b)
{
return ((struct PeoInfo*)a)->age - ((struct PeoInfo*)b)->age;
}
void SortContactAge(Contact* pc)
{
assert(pc);
qsort(pc->data, pc->sz, sizeof(pc->data[0]), cmp_age);
}
这个操作在初始化通讯录的时候完成
void LoadContact(Contact* pc)
{
//打开文件
FILE* pf = fopen("contact.dat", "rb");
if (pf == NULL)
{
perror("LoadContact");
return;
}
//读文件
PeoInfo tmp = { 0 };
while (fread(&tmp, sizeof(PeoInfo), 1, pf))
{
if (0 == CheckCapacity(pc))
return;
pc->data[pc->sz] = tmp;
pc->sz++;
}
//关闭文件
fclose(pf);
pf = NULL;
}
//初始化通讯录
void InitContact(Contact* pc)
{
assert(pc);
pc->data = (PeoInfo*)malloc(DEFAULT_SZ * sizeof(PeoInfo));
if (pc->data == NULL)
{
perror("InitContact");
return;
}
pc->sz = 0;
pc->capacity = DEFAULT_SZ;
//文件中保存的信息加载到通讯录中
LoadContact(pc);
}
void SaveContact(Contact* pc)
{
FILE* pf = fopen("contact.dat", "wb");
if (pf == NULL)
{
perror("SaveContact");
return;
}
//写数据
int i = 0;
for (i = 0; i < pc->sz; i++)
{
fwrite(pc->data + i, sizeof(PeoInfo), 1, pf);
}
//关闭文件
fclose(pf);
pf = NULL;
}
#pragma once
#include
#include
#include
#include
#define MAX 100
#define MAX_NAME 20
#define MAX_SEX 5
#define MAX_TELE 12
#define MAX_ADDR 30
#define DEFAULT_SZ 3
#define INC_SZ 2
enum OPTION
{
EXIT,//0
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;
//动态版本
typedef struct Contact
{
PeoInfo* data; //指向了存放数据的空间
int sz; //记录的当前放的有效元素的个数
int capacity; //通讯录当前的最大容量
}Contact;
int CheckCapacity(Contact* pc)
{
if (pc->sz == pc->capacity)
{
PeoInfo* ptr = (PeoInfo*)realloc(pc->data, (pc->capacity + INC_SZ) * sizeof(PeoInfo));
if (ptr == NULL)
{
perror("CheckCapacity");
return 0;
}
else
{
pc->data = ptr;
pc->capacity += INC_SZ;
printf("增容成功\n");
return 1;
}
}
return 1;
}
void LoadContact(Contact* pc)
{
//打开文件
FILE* pf = fopen("contact.dat", "rb");
if (pf == NULL)
{
perror("LoadContact");
return;
}
//读文件
PeoInfo tmp = { 0 };
while (fread(&tmp, sizeof(PeoInfo), 1, pf))
{
if (0 == CheckCapacity(pc))
return;
pc->data[pc->sz] = tmp;
pc->sz++;
}
//关闭文件
fclose(pf);
pf = NULL;
}
//初始化通讯录
void InitContact(Contact* pc)
{
assert(pc);
pc->data = (PeoInfo*)malloc(DEFAULT_SZ * sizeof(PeoInfo));
if (pc->data == NULL)
{
perror("InitContact");
return;
}
pc->sz = 0;
pc->capacity = DEFAULT_SZ;
//文件中保存的信息加载到通讯录中
LoadContact(pc);
}
//增加联系人
//静态版本
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].tele);
printf("请输入地址:>");
scanf("%s", pc->data[pc->sz].addr);
pc->sz++;
printf("成功增加联系人\n");
}
//动态的版本
//扩容函数
void AddContact(Contact* pc)
{
assert(pc);
if (0 == CheckCapacity(pc))
{
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].tele);
printf("请输入地址:>");
scanf("%s", pc->data[pc->sz].addr);
pc->sz++;
printf("成功增加联系人\n");
}
//显示所有联系人的信息
void ShowContact(const Contact* pc)
{
assert(pc);
if (pc->sz == 0)
{
printf("当前通讯录暂无联系人数据\n");
return;
}
int i = 0;
//打印列标题
printf("%-10s\t%-4s\t%-5s\t%-12s\t%-30s\n", "名字", "年龄", "性别", "电话", "地址");
//打印数据
for (i = 0; i < pc->sz; i++)
{
printf("%-10s\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);
}
}
//删除指定联系人
//查找联系人的位置
static int 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)
{
if (pc->sz == 0)
{
printf("通讯录为空,无法删除\n");
return;
}
char name[MAX_NAME] = { 0 };
assert(pc);
//删除
printf("请输入要删除的人名字:>");
scanf("%s", name);
//找到要删除的人
int del = FindByName(pc, name);
if (del == -1)
{
printf("要删除的人不存在\n");
return;
}
int i = 0;
//删除坐标位del的联系人
for (i = del; 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[MAX_NAME] = { 0 };
printf("请输入要查找人的名字:>");
scanf("%s", name);
int pos = FindByName(pc, name);
if (pos == -1)
printf("要查找的人不存在\n");
else
{
printf("%-10s\t%-4s\t%-5s\t%-12s\t%-30s\n", "名字", "年龄", "性别", "电话", "地址");
//打印数据
printf("%-10s\t%-4d\t%-5s\t%-12s\t%-30s\n",
pc->data[pos].name,
pc->data[pos].age,
pc->data[pos].sex,
pc->data[pos].tele,
pc->data[pos].addr);
}
}
//修改指定联系人
void ModifyContact(Contact* pc)
{
assert(pc);
char name[MAX_NAME] = { 0 };
printf("请输入要修改人的名字:>");
scanf("%s", name);
int pos = FindByName(pc, name);
if (pos == -1)
printf("要修改的人不存在\n");
else
{
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].tele);
printf("请输入地址:>");
scanf("%s", pc->data[pos].addr);
printf("修改成功\n");
}
}
//销毁通讯录
void DestroyContact(Contact* pc)
{
free(pc->data);
pc->data = NULL;
pc->capacity = 0;
pc->sz = 0;
}
//保存通讯录信息到文件
void SaveContact(Contact* pc)
{
FILE* pf = fopen("contact.dat", "wb");
if (pf == NULL)
{
perror("SaveContact");
return;
}
//写数据
int i = 0;
for (i = 0; i < pc->sz; i++)
{
fwrite(pc->data + i, sizeof(PeoInfo), 1, pf);
}
//关闭文件
fclose(pf);
pf = NULL;
}
int cmp_name(const void* a, const void* b)
{
return strcmp((char*)a, (char*)b);
}
int cmp_age(const void* a,const void* b)
{
return ((struct PeoInfo*)a)->age - ((struct PeoInfo*)b)->age;
}
void SortContactName(Contact* pc)
{
assert(pc);
qsort(pc->data, pc->sz, sizeof(pc->data[0]), cmp_name);
printf("排序成功\n");
}
void SortContactAge(Contact* pc)
{
assert(pc);
qsort(pc->data, pc->sz, sizeof(pc->data[0]), cmp_age);
}
#define _CRT_SECURE_NO_WARNINGS
#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");
printf("********************************\n");
}
void Sort(Contact* pc)
{
printf("您想用哪种方式排序:1,按名字排序 2,按年龄排序\n");
printf("请选择:>");
int x = 0;
scanf_s("%d", &x);
if (x == 1)
{
SortContactName(pc);
}
else if (x == 2)
{
SortContactAge(pc);
}
else
{
printf("选择错误");
}
printf("排序成功\n");
}
void test()
{
int input = 0;
//首先得有通讯录
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:
Sort(&con);
break;
case EXIT:
SaveContact(&con);
DestroyContact(&con);
printf("退出通讯录\n");
break;
default:
printf("选择错误, 重新选择\n");
break;
}
} while (input);
}
int main()
{
test();
return 0;
}