目录
通讯录基本要求:
实现功能:
一、打印菜单:
二、联系人信息存储
三、通讯录初始化及功能:
1、静态存储通讯录
(1)、通讯录信息:
(2)、初始化通讯录:
(3)、通讯录功能:
2、动态存储通讯录
(1)、通讯录信息:
(2)、初始化通讯录:
(3)、通讯录功能:
四、通讯录主函数:
通讯录基本要求:
??????????????????????????????????????? ? ?存储人数:100
? ? ? ? ? ? ? ? ? ? ? ? ? ???人员信息:?姓名、性别、年龄、电话、住址
实现功能:
????????????????????????添加联系人信息
????????????????????????删除联系人信息
????????????????????????查找联系人信息
????????????????????????修改联系人信息
????????????????????????显示联系人信息
? ? ? ? ????????????????按名字排序所有联系人
一、打印菜单:
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");
}
二、联系人信息存储
先定义一个peoinfo的结构体 ,用来存放联系人的基本信息,成员包括name、sex、tele、age、addr。
//联系人信息:
struct peoinfo
{
char name[MAX_NAME];
char sex[MAX_SEX];
char tele[MAX_TELE];
int age;
char addr[MAX_ADDR];
};
??
三、通讯录初始化及功能:
1、静态存储通讯录
(1)、通讯录信息:
然后再定义一个contact的结构体,里面用来存放结构体peoinfo 和通讯录内联系人的个数sz。
struct contact
{
struct peoinfo data[MAX];
int sz;
};
?
(2)、初始化通讯录:
void initcontact(struct contact* pc)
{
assert(pc);
pc->sz = 0;
memset(pc->data, 0, MAX * sizeof(struct peoinfo));
}
初始化时先断言是否为空。然后分开初始化,利用结构体的访问形式pc->sz = 0,对于数组,我们利用内存设置函数memset来初始化,以字节为单位一个字节一个字节的初始化!
(3)、通讯录功能:
? ? ? ? 1.添加联系人
在添加新的联系人时,首先断言是否为空;然后要看通信录是否还有空间,进行通讯录是否为满判断,若没有空间则结束进程,若有空间则输入个人的信息存储到数组里;添加完成后sz++
void addcontact(struct contact* pc)
{
assert(pc);
if (pc->sz==MAX)
{
printf("通讯录已满,无法添加数据!!!\n");
return;
}
//增加信息
printf("请输入姓名:");
scanf("%s", pc->data[pc->sz].name);
printf("请输入性别:");
scanf("%s", pc->data[pc->sz].sex);
printf("请输入年龄:");
scanf("%d", &(pc->data[pc->sz].age));
printf("请输入电话:");
scanf("%s", pc->data[pc->sz].tele);
printf("请输入地址:");
scanf("%s", pc->data[pc->sz].addr);
pc->sz++;
printf("添加联系人成功!\n");
}
? ? ? ? 2.删除联系人
删除联系人之前先进行按姓名的人员查找,包括下面的查找联系人、修改联系人都需要用到这个查找,所以我们就不妨封装一个函数——遍历整个数组通过名字来进行查找,找到就返回下标,找不到返回-1;
通过查找函数先判断通讯里面是否存在人员,不存在就不需要操作,结束进程;若存在则删除表中人员的信息——只需要把ret后的数据依次往前移动,覆盖掉前一个位置的信息就可以了。删除成功后把sz--。
int findname(const struct contact* pc, char name[])
{
for (int i = 0; i < pc->sz; i++)
if (0 == strcmp(pc->data[i].name, name))
return i;
return -1;
}
void delecontact(struct contact* pc)
{
char name[MAX_NAME];
printf("请输入要删除的联系人姓名:");
scanf("%s", name);
int ret = findname(pc, name);
if (ret == -1)
printf("不存在!!!\n");
else
{
pc->data[ret] = pc->data[pc->sz];
pc->sz--;
printf("删除成功\n");
}
}
????????3.查找联系人
运用之前的查找函数根据姓名进行查找,若返回-1则找不到结束进程;若找到了,根据返回的ret下标,打印信息即可!
void searchcontact(const struct contact* pc)
{
char name[MAX_NAME];
printf("输入要查找的人姓名:");
scanf("%s", name);
int ret = findname(pc, name);
if (ret == -1)
printf("要查找的人不存在!\n");
else
{
printf("%-20s\t%-5s\t%-5s\t%-12s\t%-30s\n", "姓名","性别", "年龄", "电话", "地址");
printf("%-20s\t%-5s\t%-5d\t%-12s\t%-30s\n", pc->data[ret].name,
pc->data[ret].sex,
pc->data[ret].age,
pc->data[ret].tele,
pc->data[ret].addr);
}
}
? ? ? ? 4.展示联系人
首先先打印一个标题,增加可读性!然后在利用for循环打印信息。默认是左对齐的、负号代表右对齐。所以在这里为了美观性我们可以用负号进行右对齐
void showcontact(const struct contact* pc)
{
printf("%-20s\t%-5s\t%-5s\t%-12s\t%-30s\n", "姓名", "性别", "年龄", "电话", "地址");
for (int i = 0; i < pc->sz; i++)
{
printf("%-20s\t%-5s\t%-5d\t%-12s\t%-30s\n", pc->data[i].name,
pc->data[i].sex,
pc->data[i].age,
pc->data[i].tele,
pc->data[i].addr);
}
}
? ? ? ? 5.修改联系人
通过查找函数根据姓名进行查找,找不到就返回-1结束进程;找到了则根据返回的下标ret,再次输入信息覆盖之前的信息。
void modifycontact(struct contact* pc)
{
printf("请输入要修改的人的姓名:");
char name[MAX_NAME];
scanf("%s", name);
int ret = findname(pc, name);
if (ret == -1)
printf("要修改的人不存在!!!\n");
else
{
printf("输入姓名:");
scanf("%s", pc->data[ret].name);
printf("输入性别:");
scanf("%s", pc->data[ret].sex);
printf("输入年龄:");
scanf("%d", &(pc->data[ret].age));
printf("输入电话:");
scanf("%s", pc->data[ret].tele);
printf("输入地址:");
scanf("%s", pc->data[ret].addr);
printf("修改成功!!!");
}
}
? ? ? ? 6.按照联系人姓名排序
在这里我们可以运用 qsort() 函数进行排序!
int cmpname(const void* p1, const void* p2)
{
return(strcmp(((struct peoinfo*)p1)->name, ((struct peoinfo*)p2)->name));
}
void sortcontact(struct contact* pc)
{
qsort(pc->data, pc->sz, sizeof(struct peoinfo), cmpname);
}
?注:这个通讯录我们采用静态存储的模式即顺序表的方式来实现,但是静态存储的通讯录对于内存的利用不是很有效,存在着一些明显的弊端,当存储人数少时,存在空间浪费现象;当人数达到设置值时便不能再进行存储,存在空间不足的现象。因此下面的动态存储通讯录便是基于此的优化!?
2、动态存储通讯录
(1)、通讯录信息:
相比于静态存储,这里可以利用指针动态创建内存,此外还增加了一个变量来记录当前内存的容量
struct contact
{
struct peoinfo *data; //指向了存放数据的空间
int sz; //已经放进去的信息
int capacity; //容量
};
?
(2)、初始化通讯录:
void initcontact(struct contact* pc)
{
assert(pc);
pc->data = (struct peoinfo*)malloc(DEFAULT_SZ * sizeof(struct peoinfo));
if (pc->data == NULL)
{
perror("initcontact");
return;
}
pc->sz = 0;
pc->capacity = DEFAULT_SZ;
}
(3)、通讯录功能:
? ? ? ? 1.添加联系人
static int check_capacity(struct contact* pc)
{
if (pc->sz == pc->capacity)
{
//增加容量
struct peoinfo* ptr = realloc(pc->data, (pc->capacity + INC_SZ) * sizeof(struct peoinfo));
if (ptr != NULL)
{
pc->data = ptr;
pc->capacity += INC_SZ;
printf("增容成功!\n");
return 1;
}
else
{
perror("addcontact");
return 0;
}
}
else
return 1;
}
void addcontact(struct contact* pc)
{
assert(pc);
if (0 == check_capacity(pc))
{
return;
}
//增加信息
printf("请输入姓名:");
scanf("%s", pc->data[pc->sz].name);
printf("请输入性别:");
scanf("%s", pc->data[pc->sz].sex);
printf("请输入年龄:");
scanf("%d", &(pc->data[pc->sz].age));
printf("请输入电话:");
scanf("%s", pc->data[pc->sz].tele);
printf("请输入地址:");
scanf("%s", pc->data[pc->sz].addr);
pc->sz++;
printf("添加联系人成功!\n");
}
? ? ? ? 2.删除联系人
void delecontact(struct contact* pc)
{
char name[MAX_NAME];
printf("请输入要删除的联系人姓名:");
scanf("%s", name);
int ret = findname(pc, name);
if (ret == -1)
printf("不存在!!!\n");
else
{
for (int j = ret; j < pc->sz - 1; j++)
{
pc->data[j] = pc->data[j + 1];
}
pc->sz--;
printf("成功删除指定联系人\n");
}
}
????????3.查找联系人
void searchcontact(const struct contact* pc)
{
char name[MAX_NAME];
printf("输入要查找的人姓名:");
scanf("%s", name);
int ret = findname(pc, name);
if (ret == -1)
printf("要查找的人不存在!\n");
else
{
printf("%-20s\t%-5s\t%-5s\t%-12s\t%-30s\n", "姓名", "性别", "年龄", "电话", "地址");
printf("%-20s\t%-5s\t%-5d\t%-12s\t%-30s\n", pc->data[ret].name,
pc->data[ret].sex,
pc->data[ret].age,
pc->data[ret].tele,
pc->data[ret].addr);
}
}
? ? ? ? 4.展示联系人
void showcontact(const struct contact* pc)
{
printf("%-20s\t%-5s\t%-5s\t%-12s\t%-30s\n", "姓名", "性别", "年龄", "电话", "地址");
for (int i = 0; i < pc->sz; i++)
{
printf("%-20s\t%-5s\t%-5d\t%-12s\t%-30s\n", pc->data[i].name,
pc->data[i].sex,
pc->data[i].age,
pc->data[i].tele,
pc->data[i].addr);
}
}
? ? ? ? 5.修改联系人
void modifycontact(struct contact* pc)
{
printf("请输入要修改的人的姓名:");
char name[MAX_NAME];
scanf("%s", name);
int ret = findname(pc, name);
if (ret == -1)
printf("要修改的人不存在!!!\n");
else
{
printf("输入姓名:");
scanf("%s", pc->data[ret].name);
printf("输入性别:");
scanf("%s", pc->data[ret].sex);
printf("输入年龄:");
scanf("%d", &(pc->data[ret].age));
printf("输入电话:");
scanf("%s", pc->data[ret].tele);
printf("输入地址:");
scanf("%s", pc->data[ret].addr);
printf("修改成功!!!");
}
}
? ? ? ? 6.按照联系人姓名排序
int cmpname(const void* p1, const void* p2)
{
return(strcmp(((struct peoinfo*)p1)->name, ((struct peoinfo*)p2)->name));
}
//按照姓名来排序
void sortcontact(struct contact* pc)
{
qsort(pc->data, pc->sz, sizeof(struct peoinfo), cmpname);
}
????????7.销毁通讯录?
释放pc->data指针,并手动置为NULL,把sz和capacity置为0
销毁通讯录可以不写在菜单里,直接写到退出通讯录里面,当退出时直接调用这个销毁函数。
void destroycontact(struct contact* pc)
{
free(pc->data);
pc->data = NULL;
pc->capacity = 0;
pc->sz = 0;
}
四、通讯录主函数:
int main()
{
int input = 0;
struct contact con;
//初始化
initcontact(&con);
do
{
menu();
printf("输入选择:");
scanf("%d", &input);
switch (input)
{
case 1:
addcontact(&con);
break;
case 2:
delecontact(&con);
break;
case 3:
searchcontact(&con);
break;
case 4:
modifycontact(&con);
break;
case 5:
showcontact(&con);
break;
case 6:
sortcontact(&con);
break;
case 0:
//destroycontact(&con); //动态存储时使用
printf("退出");
break;
default:
printf("输入错误");
break;
}
} while (input);
return 0;
}
|