在上一篇博客中,小编已经详细介绍了静态版的通讯录的完整实现过程。此篇博客也是按照之前的模板进行改动,因此很多没有改动的地方没有详细介绍,想深入了解的同学可以先看一下小编上一篇博客,链接会放在本文的底端。
对于了解静态版通讯录的同学,大家一定会发现静态通讯录存在的一个最大问题就是无法自动扩容,当信息存满了,就无法继续添加联系人。针对这个问题,本文将利用动态开辟内存来解决。
目录
以下对改动部分进行详细分析
1定义通讯录结构体
静态通讯录版本
struct Contact
{
struct PeoInfo data[MAX];
int sz;
};
动态通讯录版本
struct Contact
{
struct PeoInfo* data;
int sz;
int capacity;
};
我们可以很清楚的看到,对原先静态通讯录的改动有两处,一是将数组改成了指针,用于指向动态开辟内存,二是增加了capacity变量用于记录通讯录的容量。
2初始化通讯录
静态通讯录版本
void InitContact(struct Contact* pc)
{
assert(pc);
pc->sz = 0;
memset(pc->data, 0, MAX * sizeof(struct PeoInfo));
}
动态通讯录版本
void InitContact(struct Contact* pc)
{
assert(pc);
pc->data = (struct PeoInfo*)malloc(sizeof(struct PeoInfo) * DEFAULT_SZ);
if (pc->data == NULL)
{
perror("InitContact()");
return;
}
pc->sz = 0;
pc->capacity = DEFAULT_SZ;
}
在这里,小编通过利用malloc进行动态内存开辟,同时利用宏定义DEFAYLT_SZ来控制初始化是开辟空间的大小,此段代码中所用的DEFAYLT_SZ的大小为3。注意我们要对malloc开辟的空间进行判断,看看是否开辟成功。
3添加联系人信息
静态通讯录版本
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");
}
动态通讯录版本
static int check_capacity(struct Contact* pc)
{
if (pc->sz == pc->capacity)
{
struct PeoInfo* ptr = (struct PeoInfo*)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);
//判断通讯录是否已满
int ret = check_capacity(pc);
if (0 == ret)
{
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");
}
在这一步,动态版与静态版的最大不同点就体现了出来,在动态版本中,封装了一个check_capacity函数,专门用于检查通讯录是否满额,如果满了就会自动重新调整通讯录的空间大小,增加INC_SZ(宏定义 此处值为2)个空间 。
关于realloc函数我们也要注意,不能直接用data来接收realloc函数的返回值,如果开辟空间失败,那么原先data所指向的空间就会丢失。因此,需要一个临时变量来接收,进行判断空间开辟成功后,再让data指向这块空间。
4通讯录销毁,空间释放
void DestroyContact(struct Contact* pc)
{
assert(pc);
free(pc->data);
pc->data = NULL;
pc->capacity = 0;
pc->sz = 0;
}
在动态通讯录中,最后的空间释放是非常重要的,一个程序运行,如果不释放空间最终会导致内存不够用,从而导致程序崩溃。当然释放空间的操作比较简单,直接使用free释放掉空间,同时也要将指针置空。
好了,以上就是与静态版通讯录不同的地方,其余部分是一样的。
5完整代码
5.1主函数实现
#define _CRT_SECURE_NO_WARNINGS 1
#include"D_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");
}
enum INPUT
{
EXIT,
ADD,
DEL,
SEARCH,
MODIFY,
SHOW,
SORT
};
int main()
{
int input = 0;
//定义通讯录
struct 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:
SortContact(&con);
break;
case EXIT:
DestroyContact(&con);
printf("退出通讯录\n");
break;
default:
printf("选择错误,请重新选择\n");
break;
}
} while (input);
return 0;
}
5.2动态版通讯录函数实现
#define _CRT_SECURE_NO_WARNINGS 1
#include"D_Contact.h"
//初始化通讯录
//void InitContact(struct Contact* pc)
//{
// assert(pc);
// pc->sz = 0;
// memset(pc->data, 0, MAX * sizeof(struct PeoInfo));
//}
void InitContact(struct Contact* pc)
{
assert(pc);
pc->data = (struct PeoInfo*)malloc(sizeof(struct PeoInfo) * DEFAULT_SZ);
if (pc->data == NULL)
{
perror("InitContact()");
return;
}
pc->sz = 0;
pc->capacity = DEFAULT_SZ;
}
//释放通讯录空间
void DestroyContact(struct Contact* pc)
{
assert(pc);
free(pc->data);
pc->data = NULL;
pc->capacity = 0;
pc->sz = 0;
}
//增加人的信息到通讯录
//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");
//}
static int check_capacity(struct Contact* pc)
{
if (pc->sz == pc->capacity)
{
struct PeoInfo* ptr = (struct PeoInfo*)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);
//判断通讯录是否已满
int ret = check_capacity(pc);
if (0 == ret)
{
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");
}
//显示通讯录信息
void ShowContact(const struct Contact* pc)
{
int i = 0;
printf("%-20s\t%-6s\t%-5s\t%-12s\t%-30s\n", "姓名", "性别", "年龄", "电话", "地址");
for (i = 0; i < pc->sz; i++)
{
printf("%-20s\t%-6s\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);
}
}
static int FindByName(const struct Contact* pc, char name[])
{
int i = 0;
int ret = -1;
for (i = 0; i < pc->sz; i++)
{
ret = strcmp(pc->data[i].name, name);
if (0 == ret)
return i;
}
return -1;
}
//删除指定联系人
void DelContact(struct Contact* pc)
{
assert(pc);
//首先得找到要删除联系人的信息
printf("请输入要删除联系人的姓名:>");
char name[MAX_NAME] = { 0 };
scanf("%s", name);
int ret = FindByName(pc, name);
if (ret == -1)
{
printf("要删除的人不存在\n");
}
else
{
int i = 0;
for (i = ret; i < pc->sz - 1; i++)
{
pc->data[i] = pc->data[i + 1];
}
pc->sz--;
printf("成功删除指定联系人\n");
}
}
//查找指定联系人
void SearchContact(const struct Contact* pc)
{
char name[MAX_NAME];
printf("请输入要查找的人的名字:>");
scanf("%s", name);
//查找一下指定的人是否存在
int ret = FindByName(pc, name);
if (ret == -1)
printf("要查找的人不存在\n");
else
{
printf("%-20s\t%-6s\t%-5s\t%-12s\t%-30s\n", "姓名", "性别", "年龄", "电话", "地址");
printf("%-20s\t%-6s\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);
}
}
//修改指定联系人的信息
void ModifyContact(struct Contact* pc)
{
char name[MAX_NAME];
printf("请输入要修改的人的名字:>");
scanf("%s", name);
//查找一下要修改的人是否存在
int ret = FindByName(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("修改联系人成功\n");
}
}
int compare_age(const void* e1, const void* e2)
{
return ((struct Contact*)e1)->data->age - ((struct Contact*)e2)->data->age;
}
//排序通讯录中的信息 - 年龄
void SortContact(struct Contact* pc)
{
qsort(pc->data, pc->sz, sizeof(struct PeoInfo), compare_age);
}
5.3动态版通讯录函数声明及头文件
#pragma once
#include<stdio.h>
#include<string.h>
#include<assert.h>
#include<stdlib.h>
#define MAX 1000
#define MAX_NAME 20
#define MAX_SEX 20
#define MAX_TELE 20
#define MAX_ADDR 20
#define DEFAULT_SZ 3 //通讯录容量
#define INC_SZ 2 //空间不够时,增加的个数
struct PeoInfo
{
char name[20];
char sex[6];
int age;
char tele[20];
char addr[20];
};
struct Contact
{
//struct PeoInfo data[MAX];
struct PeoInfo* data;
int sz;
int capacity;
};
//初始化通讯录
void InitContact(struct Contact* p);
//增加人的信息到通讯录
void AddContact(struct Contact* pc);
//显示通讯录中的信息
void ShowContact(const struct Contact* pc);
//删除指定联系人
void DelContact(struct Contact* pc);
//查找指定联系人
void SearchContact(const struct Contact* pc);
//修改指定联系人的信息
void ModifyContact(struct Contact* pc);
//排序通讯录中的信息 - 年龄
void SortContact(struct Contact* pc);
//退出通讯录,释放空间
void DestroyContact(struct Contact* pc);
静态版通讯录链接:https://blog.youkuaiyun.com/xiaoHu_C/article/details/126992178?spm=1001.2014.3001.5501