通讯录第二个版本——动态版本
之前和大家分享了我写的通讯录的静态版本,它的特点就是大小是固定的,后面修改不太容易,但是我们生活中很多时候都不知道到底需要多大的空间来存储通讯录联系人的信息,如果小了不够用,如果大了又会造成空间浪费,那么我们能不能让这个通讯录自己扩容呢,一旦快满了就让他自己扩大存储空间呢?答案是可以的,本篇博客就将讲述如果创建一个可以自动扩容的通讯录,也就是通讯录三个版本里面的第二种——动态版本。
`
文章目录
前言
既然要设计一个动态版本的通讯里,就必须用到动态内存管理的几个函数,realloc,malloc,free,之前的博客已经详细讲述了这几种函数的用法,下面就不再赘述,直接进入主题,动态通讯录的设计。
一、通讯里简介
我们将通讯录写在三个文件中,分别是头文件contacts.h和两个源文件dynamic contact.c,test.c,头文件存放函数的声明以及结构体的定义,dynamic contact.c用来存储通讯录功能实现的代码,test.c用来存放菜单函数和main函数,最终测试。
二、头文件
代码如下(示例):
#define _CRT_SECURE_NO_WARNINGS 1
#define _CRT_SECURE_NO_WARNINGS 1
#define max 3
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<math.h>
#include <windows.h>
//初始化通讯录
void inicontact(struct contact* pc);
//添加联系人
void addpeople(struct contact* pc);
//删除联系人
void delpeople(struct contact* pc);
//展示联系人
void showpeople(struct contact* pc);
//查找联系人
void searchpeople(struct contact* pc);
//修改联系人
void revisepeople(struct contact* pc);
//联系人排序
void sortpeople(struct contact* pc);
//清除联系人
void deadpeople(struct contact* pc);
int cmp(struct contact* pc);
struct PeoInfo
{
char name[10];
char sex[5];
int age;
char tel[15];
char address[20];
};
struct contact
{
struct PeoInfo* date;
int sz;
int max;
};
在这里我们使用了结构体的嵌套以及#define 宏定义,这样做是为了方便后面的使用。
二、通讯录七大功能的实现
#define _CRT_SECURE_NO_WARNINGS 1
#include "contacts.h"
void menu()
{
printf("------------------------------------\n");
printf("--------请选择你要实现的功能--------\n");
printf("--------1.添加联系人信息------------\n");
printf("--------2.删除指定联系人信息--------\n");
printf("--------3.查找指定联系人信息--------\n");
printf("--------4.修改指定联系人信息--------\n");
printf("--------5.显示所有联系人信息--------\n");
printf("--------6.清空所有联系人------------\n");
printf("--------7.以名字排序所有联系人------\n");
void inicontact(struct contact* pc)
{
pc->sz = 0;
pc->max = 3;
pc->date = (struct PeoInfo*)calloc(3, sizeof(struct PeoInfo));
}
void addpeople(struct contact* pc)
{
if ((pc->sz) >= (pc->max))
{
pc = (struct PeoInfo*)realloc(pc->date, (pc->max + 2) * sizeof(struct PeoInfo));
printf("扩容成功\n");
pc->max += 2;
}
printf("请输入姓名\n");
scanf("%s", &(pc->date[pc->sz].name));
printf("请输入性别\n");
scanf("%s", &(pc->date[pc->sz].sex));
printf("请输入年龄\n");
scanf("%d", &(pc->date[pc->sz].age));
printf("请输入电话\n");
scanf("%s", &(pc->date[pc->sz].tel));
printf("请输入住址\n");
scanf("%s", &(pc->date[pc->sz].address));
printf("添加联系人完毕\n");
pc->sz++;
}
void delpeople(struct contact* pc)
{
char name1[10];
int input1;
printf("请输入你要删除的联系人\n");
scanf("%s", &name1);
int i;
for (i = 0; i < (pc->sz); i++)
{
if (strcmp(pc->date[i].name, name1) == 0)
{
printf("查到到联系人%s是否确认删除\n", name1);
scanf("%d", &input1);
if (input1 == 1)
{
for (int j = i; j < ((pc->sz) - 1); j++)
{
(pc->date[j]) = (pc->date[j + 1]);
pc->sz--;
}
printf("删除成功\n");
}
else
{
printf("成功取消\n");
}
}
}
if (i >= (pc->sz))
{
printf("联系人%s不存在\n", name1);
}
}
void searchpeople(struct contact* pc)
{
char name1[10];
printf("请输入你要查找的联系人\n");
scanf("%s", &name1);
int i;
for (i = 0; i < (pc->sz); i++)
{
if (strcmp(pc->date[i].name, name1) == 0)
{
printf("%-10s\t %-15s\t %-3s\t %-15s\t %-20s\t\n",
"name", "sex", "age", "tel", "address");
printf("%-10s\t %-15s\t %-3d\t %-15s\t %-20s\t\n",
pc->date[i].name,
pc->date[i].sex,
pc->date[i].age,
pc->date[i].tel,
pc->date[i].address);
}
}
if (i > pc->sz)
{
printf("不存在此联系人%s\n", name1);
}
}
void revisepeople(struct contact* pc)
{
char name1[10];
printf("请输入你要修改的联系人\n");
scanf("%s", &name1);
int i;
for (i = 0; i < (pc->sz); i++)
{
if (strcmp(pc->date[i].name, name1) == 0)
{
printf("请输入姓名\n");
scanf("%s", &(pc->date[i].name));
printf("请输入性别\n");
scanf("%s", &(pc->date[i].sex));
printf("请输入年龄\n");
scanf("%d", &(pc->date[i].age));
printf("请输入电话\n");
scanf("%s", &(pc->date[i].tel));
printf("请输入住址\n");
scanf("%s", &(pc->date[i].address));
printf("修改联系人完毕\n");
}
}
if (i > pc->sz)
{
printf("不存在此联系人%s\n", name1);
}
}
void showpeople(struct contact* pc)
{
int i;
printf("%-10s\t %-15s\t %-3s\t %-15s\t %-20s\t\n",
"name", "sex", "age", "tel", "address");
for (i = 0; i < (pc->sz); i++)
{
printf("%-10s\t %-15s\t %-3d\t %-15s\t %-20s\t\n",
pc->date[i].name,
pc->date[i].sex,
pc->date[i].age,
pc->date[i].tel,
pc->date[i].address);
}
}
int cmp(void* e1, void* e2)
{
return strcmp(((struct PeoInfo*)e1)->name ,((struct PeoInfo*)e2)->name);
}
void sortpeople(struct contact* pc)
{
qsort(pc, pc->sz, sizeof(struct PeoInfo), cmp);
}
void deadpeople(struct contact* pc)
{
free(pc->date);
pc->date = NULL;
pc->max = 0;
pc->sz = 0;
}
我们这里一共有7个功能,
1.添加联系人信息
2.删除指定联系人信息
3.查找指定联系人信息
4.修改指定联系人信息
5.显示所有联系人信息
6.清空所有联系人
7.以名字排序所有联系人
1.添加联系人信息
void addpeople(struct contact* pc)
{
if ((pc->sz) >= (pc->max))
{
pc = (struct PeoInfo*)realloc(pc->date, (pc->max + 2) * sizeof(struct PeoInfo));
printf("扩容成功\n");
pc->max += 2;
}
printf("请输入姓名\n");
scanf("%s", &(pc->date[pc->sz].name));
printf("请输入性别\n");
scanf("%s", &(pc->date[pc->sz].sex));
printf("请输入年龄\n");
scanf("%d", &(pc->date[pc->sz].age));
printf("请输入电话\n");
scanf("%s", &(pc->date[pc->sz].tel));
printf("请输入住址\n");
scanf("%s", &(pc->date[pc->sz].address));
printf("添加联系人完毕\n");
pc->sz++;
}
我们联系人的数量是sz,在添加联系人之前我们要和结构体中的max比较,如果sz>=max我们就要对其进行扩容,我们在初始化的使用用的calloc函数动态内存开辟了结构体指针所指向的空间,我们如果要扩容就是用realloc函数来实现,我们每次在原有基础上增加两个大小为是struct PeoInfo的空间,同时sz++,max也要+2…得到足够的空间了我们便可以正常的增加联系人到通讯录。
我们在这里和之前的原始版本比较一下:
void AddContact(struct Contact* pc)
{
assert(pc);
if (pc->sz == MAX)
{
printf("通讯录已满,无法添加新用户");
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].adder);
pc->sz++;
printf("添加新用户成功!");
}
这里我们明显可以看到原来第一个版本大小不可以更改,如果满了之后就只能打印通讯录已满,很难满足日常需求,所以动态版本是很有必要的!
2.删除指定联系人信息
代码如下(示例):
void delpeople(struct contact* pc)
{
char name1[10];
char input1;
printf("请输入你要删除的联系人\n");
scanf("%s", &name1);
int i;
for (i = 0; i < (pc->sz); i++)
{
if (strcmp(pc->date[i].name, name1) == 0)
{
printf("查到到联系人%s是否确认删除\n", name1);
scanf("%d", &input1);
if (input1 == 'Y'||'y')
{
for (int j = i; j < ((pc->sz) - 1); j++)
{
(pc->date[j]) = (pc->date[j + 1]);
pc->sz--;
}
printf("删除成功\n");
}
else
{
printf("成功取消\n");
}
}
}
if (i >= (pc->sz))
{
printf("联系人%s不存在\n", name1);
}
}
我们先创建一个数组用来输入我们要删除人的姓名,在for循环中利用strcmp函数比较通讯录中联系人的姓名和我们想删除联系人的姓名,如果找到了就打印是否删除联系人,我们输入Y或者y就表示确认删除,之后利用for循环不停的用后一个数据来覆盖前一个数据,达到删除的目的。
3.查找指定联系人信息
代码如下(示例):
void searchpeople(struct contact* pc)
{
char name1[10];
printf("请输入你要查找的联系人\n");
scanf("%s", &name1);
int i;
for (i = 0; i < (pc->sz); i++)
{
if (strcmp(pc->date[i].name, name1) == 0)
{
printf("%-10s\t %-15s\t %-3s\t %-15s\t %-20s\t\n",
"name", "sex", "age", "tel", "address");
printf("%-10s\t %-15s\t %-3d\t %-15s\t %-20s\t\n",
pc->date[i].name,
pc->date[i].sex,
pc->date[i].age,
pc->date[i].tel,
pc->date[i].address);
}
}
if (i > pc->sz)
{
printf("不存在此联系人%s\n", name1);
}
}
我们还是设置一个数组用来存放要查找联系人的姓名,然后在for循环中利用strcmp函数比较要查找的联系人和通讯录里的联系人姓名是否一样,如果一样strcmp函数返回的是0,这个时候我们利用\t按照表格的形式将其打印出来,如果查找完所有的联系人还是没有相同的就输出不存在此联系人。
4.修改指定联系人信息
代码如下(示例):
void revisepeople(struct contact* pc)
{
char name1[10];
printf("请输入你要修改的联系人\n");
scanf("%s", &name1);
int i;
for (i = 0; i < (pc->sz); i++)
{
if (strcmp(pc->date[i].name, name1) == 0)
{
printf("请输入姓名\n");
scanf("%s", &(pc->date[i].name));
printf("请输入性别\n");
scanf("%s", &(pc->date[i].sex));
printf("请输入年龄\n");
scanf("%d", &(pc->date[i].age));
printf("请输入电话\n");
scanf("%s", &(pc->date[i].tel));
printf("请输入住址\n");
scanf("%s", &(pc->date[i].address));
printf("修改联系人完毕\n");
}
}
if (i > pc->sz)
{
printf("不存在此联系人%s\n", name1);
}
}
5.显示所有联系人信息
代码如下(示例):
void showpeople(struct contact* pc)
{
int i;
printf("%-10s\t %-15s\t %-3s\t %-15s\t %-20s\t\n",
"name", "sex", "age", "tel", "address");
for (i = 0; i < (pc->sz); i++)
{
printf("%-10s\t %-15s\t %-3d\t %-15s\t %-20s\t\n",
pc->date[i].name,
pc->date[i].sex,
pc->date[i].age,
pc->date[i].tel,
pc->date[i].address);
}
}
这里就是一个简单的for循环,打印出所有的联系人。
6.清空所有联系人
代码如下(示例):
void deadpeople(struct contact* pc)
{
free(pc->date);
pc->date = NULL;
pc->max = 0;
pc->sz = 0;
}
因为我们是动态创建内存,我们最后要free掉动态创建的内存,把它归还给操作系统,同时将指针置为NULL。
7.以姓名排序所有联系人
代码如下(示例):
int cmp(void* e1, void* e2)
{
return strcmp(((struct PeoInfo*)e1)->name ,((struct PeoInfo*)e2)->name);
}
void sortpeople(struct contact* pc)
{
qsort(pc, pc->sz, sizeof(struct PeoInfo), cmp);
}
我们排序使用的是qsort函数,这个函数需要自行设计一个比较函数,我们将它命名为cmp,返回值是int,然后当作qsort的参数传入,就可以完成排序。
三、测试文件
代码如下(示例):
#define _CRT_SECURE_NO_WARNINGS 1
#include "contacts.h"
int main()
{
struct contact c1;
inicontact(&c1);
int input = 1;
do
{
menu();
scanf("%d", &input);
switch (input)
{
case 1:
system("cls");
addpeople(&c1);
break;
case 2:
system("cls");
delpeople(&c1);
break;
case 3:
system("cls");
searchpeople(&c1);
break;
case 4:
system("cls");
revisepeople(&c1);
break;
case 5:
system("cls");
showpeople(&c1);
break;
case 6:
system("cls");
inicontact(&c1);
break;
case 7:
system("cls");
sortpeople(&c1);
break;
case 0:
system("cls");
deadpeople(&c1);
break;
default:
break;
}
} while (input);
return 0;
}
在这里我们要特意介绍一下system函数,system函数代表执行系统命令,system(“cls”)就是执行命令”清屏“的意思。这样可以让我们在运行的时候看起来更加的简洁。
总结
本篇博客提供了通讯录—动态版本完整的源代码,同时对于一些要点进行了分析和讲解,针对添加联系人这一功能和之前的第一代版本----静态通讯录进行了对比,希望可以对大家有所帮助,后续会更新通讯录最终版本,可以将数据存储到对应文件中,实现真正贴近实际应用的通讯录,关注点一点不迷路,欢迎大家私信~