目录
前言
在此之前我们就已经实现了静态通讯录的一些功能,但是这个静态的通讯录的空间大小从开始就写定了,不能随意改变,例如我们给定大小为300个人的通讯录,但是我最多只有200个好友,其余的100个空间就相当于闲置浪费了,但是我们有些人跑业务需要500个甚至更多的空间,但是空间又不足。我们对于空间的需求大小,是程序运行时才知道,原来静态开辟的空间大小就不能够满足所需,我们便要进行动态开辟了。
于是我们就可以实现用多少,给多少的空间大小,既不会浪费空间也不会空间不足。
由于之前的静态通讯录比较详细,此篇重点讲解修改的地方
我们改进后的通讯录主要特点:
①:开始提供3个联系人大小的空间
②:需要添加联系人的时候扩容,每次扩容空间大小+2(也有常用的空间变为原来的2倍)
改进通讯录的类型
原来的通讯录类型:
struct Contact//大通讯录,可以记录很多人
{
struct PeoInfo date[MAX];//嵌套结构体 //存放1000个人的信息
int size;//记录当前的联系人个数
};
现在的通讯录类型:
struct Contact//大通讯录,可以记录很多人
{
struct PeoInfo * date;//date指针指向动态内存开辟的一块空间
int size;//记录当前的联系人个数
int capacity;//记录容量
};
既然我们需要动态内存开辟,我们必然少不了一个指向动态内存开辟的一个指针变量。而且随着联系人的增多,我们的容量就会慢慢变小,于是就会涉及到扩容问题,我们需要定义一个新的容量变量capacity。
改进初始化函数
void ContactInit(struct Contact* ps)//初始化通讯录,联系人个数置0
{
//初始化开辟一块空间用malloc
ps->date=(struct PeoInfo*)malloc(3 * sizeof(struct PeoInfo));//初始化3个联系人的空间
if (ps->date == NULL)
{
return;
}
ps->size = 0;
ps->capacity = 3;
}
用malloc函数开辟一块空间,返回给date指针。当前为初始化联系人个数为size=0,容量为capacity=3。
改进添加联系人函数
static int ContactCheck(struct Contact* ps)//检查当前通讯录是否已经满了,满了则扩容,扩容时失败则返回1
{
if (ps->size == ps->capacity)
{
struct PeoInfo* ptr =(struct PeoInfo*) realloc(ps->date, ps->capacity+2);//用一个ptr指针来接收首地址
if (ptr != NULL)
{
ps->date = ptr;
ps->date += 2;
return 0;//成功扩容
}
else
{
return 1;//扩容失败
}
}
}
void ContactAdd(struct Contact* ps)
{
int flag = ContactCheck(ps);
if (flag == 1)
{
printf("空间不足,增加失败\n");
return;
}
printf("请输入姓名:>");
scanf("%s", ps->date[ps->size].name);
printf("请输入年龄:->");
scanf("%d", &(ps->date[ps->size].age));
printf("请输入性别:>");
scanf("%s", ps->date[ps->size].sex);
printf("请输入电话号码:>");
scanf("%s", ps->date[ps->size].tele);
printf("请输入地址:>");
scanf("%s", ps->date[ps->size].address);
ps->size++;
printf("添加成功\n");
}
老规矩我们要先检查通讯录是否已经满了,满了则扩容容量capacity加2,扩容时失败则返回1,记得size++。设置一个flag标记,让可读性更佳!
增加销毁通讯录信息的功能
void DestroyContact(struct Contact* ps)
{
free(ps->data);//释放动态开辟空间
ps->data = NULL;
}
除了添加函数ContactAdd和检查函数ContactCheck函数需要动态内存开辟外,其他的功能函数均不需要修改,但内存开辟最重要的一点就是就得内存释放,避免造成内存泄漏
完整代码
test.dynamicContact.c:
#define _CRT_SECURE_NO_WARNINGS 1
#include"contact.h"
void menu()
{
printf("************************\n");
printf("***** Contact *****\n");
printf("***** 0.Exit *****\n");
printf("***1.Add 2.Delete ***\n");
printf("***3.Search 4.Modify ***\n");
printf("***5.Show 6.Sort ***\n");
printf("************************\n");
printf("\n");
}
int main()
{
int input = 0;
struct Contact con;//con就是通讯录,就是记录1000个人和现有联系人个数
ContactInit(&con);//初始化
do
{
menu();
printf("请输入数字来选择接下来的操作:>");
scanf("%d", &input);
switch (input)
{
case ADD: //case 1:
ContactAdd(&con);
break;
case DELETE:
ContactDelete(&con);
break;
case SEARCH:
ContactSearch(&con);
break;
case MODIFY:
ContactModify(&con);
break;
case SHOW:
ContactShow(&con);
break;
case EXIT:
printf("退出通讯录");
case SORT:
ContactSort(&con);
break;
default:
printf("选择错误,请重新选择");
break;
}
} while (input);
return 0;
}
contact.c :
#define _CRT_SECURE_NO_WARNINGS 1
#include"contact.h"
void ContactInit(struct Contact* ps)//初始化通讯录,联系人个数置0
{
//初始化开辟一块空间用malloc
ps->date=(struct PeoInfo*)malloc(3 * sizeof(struct PeoInfo));//初始化3个联系人的空间
if (ps->date == NULL)
{
return;
}
ps->size = 0;
ps->capacity = 3;
}
static int ContactCheck(struct Contact* ps)//检查当前通讯录是否已经满了,满了则扩容,扩容时失败则返回1
{
if (ps->size == ps->capacity)
{
struct PeoInfo* ptr =(struct PeoInfo*) realloc(ps->date, ps->capacity+2);//用一个ptr指针来接收首地址
if (ptr != NULL)
{
ps->date = ptr;
ps->date += 2;
return 0;//成功扩容
}
else
{
return 1;//扩容失败
}
}
}
void ContactAdd(struct Contact* ps)
{
int flag = ContactCheck(ps);
if (flag == 1)
{
printf("空间不足,增加失败\n");
return;
}
printf("请输入姓名:>");
scanf("%s", ps->date[ps->size].name);
printf("请输入年龄:->");
scanf("%d", &(ps->date[ps->size].age));
printf("请输入性别:>");
scanf("%s", ps->date[ps->size].sex);
printf("请输入电话号码:>");
scanf("%s", ps->date[ps->size].tele);
printf("请输入地址:>");
scanf("%s", ps->date[ps->size].address);
ps->size++;
printf("添加成功\n");
}
int FindByName(char name[MAX_NAME], const struct Contact* ps)//查找联系人,找到了返回下标,没找到返回-1
{
int i = 0;
for (i = 0; i < ps->size; i++)
{
if (strcmp(ps->date[i].name, name) == 0)//ps指针去找通讯录里的人,后一个name是输入的名字的指针
return i;
}
return -1;
}
void ContactDelete(struct Contact* ps)
{
char name[MAX_NAME];
printf("请输入要删除人的姓名:>");
scanf("%s", name);
int pos = FindByName(name, ps);
if (pos == -1)
{
printf("无此联系人\n");
}
else
{
int i = 0;
for (i = pos; i < ps->size - 1; i++)
{
ps->date[i] = ps->date[i + 1];//从要删除的联系人位置起,后一个联系人信息依次覆盖前一个联系人
}
printf("删除成功\n");
ps->size--;
}
}
void ContactSearch(const struct Contact* ps)//查找指定联系人并打印信息
{
char name[MAX_NAME];
printf("请输入要删除人的姓名:>");
scanf("%s", name);
int pos = FindByName(name, ps);
if (pos == -1)
{
printf("无此联系人\n");
}
else
{
printf("%-20s\t%-4s\t%-5s\t%-20s\t%-20s\n", "姓名", "年龄", "性别", "电话", "住址");
printf("%-20s\t%-4d\t%-5s\t%-20s\t%-20s\n",
ps->date[pos].name,
ps->date[pos].age,
ps->date[pos].sex,
ps->date[pos].tele,
ps->date[pos].address);
}//打印联系人的信息
}
void ContactModify(struct Contact* ps)
{
char name[MAX_NAME];
printf("请输入要修改人的姓名:>");
scanf("%s", name);
int pos = FindByName(name, ps);
if (pos == -1)
{
printf("无此联系人\n");
}
else
{
printf("请输入联系人姓名:>");
scanf("%s", ps->date[pos].name);
printf("请输入年龄:>");
scanf("%d", &(ps->date[pos].age));
printf("请输入性别:>");
scanf("%s", ps->date[pos].sex);
printf("请输入电话:>");
scanf("%s", ps->date[pos].tele);
printf("请输入住址:>");
scanf("%s", ps->date[pos].address);
printf("修改成功\n");
}
}
void ContactShow(struct Contact* ps)//打印联系人信息
{
if (ps->size == 0)
{
printf("联系人为空\n");
}
else
{
printf("%-20s\t%-4s\t%-5s\t%-20s\t%-20s\n", "姓名", "年龄", "性别", "电话", "住址");
//打印第一行信息栏
int i = 0;
for (i = 0; i < ps->size; i++)//遍历打印所有的联系人信息
{
printf("%-20s\t%-4d\t%-5s\t%-20s\t%-20s\n",
ps->date[i].name,
ps->date[i].age,
ps->date[i].sex,
ps->date[i].tele,
ps->date[i].address);
}
}
}
int CmpByName(const void* e1, const void* e2)
{
return strcmp((const char*)e1, (const char*)e2);
}
void ContactSort(struct Contact* ps)//通过名字排序
{
qsort(ps->date, ps->size, sizeof(struct PeoInfo), CmpByName);
}
//销毁通讯录
void ContactDestory(struct Contact* ps)
{
free(ps->date);
ps->date = NULL;
}
contact.h:
#define _CRT_SECURE_NO_WARNINGS 1
#pragma once
#define MAX 1000
#define MAX_NAME 20
#define MAX_SEX 5
#define MAX_TELE 20
#define MAX_ADDRESS 20
#include <string.h>
#include <stdlib.h>
#include<stdio.h>
enum Option//与结构体数组原理相同
{
EXIT,//0
ADD,//1
DELETE,//2
SEARCH,//3
MODIFY,
SHOW,
SORT
};
struct PeoInfo//每个联系人的信息
{
char name[MAX_NAME];
int age;
char sex[MAX_SEX];
int tele[MAX_TELE];
char address[MAX_ADDRESS];
};
struct Contact//大通讯录,可以记录很多人
{
struct PeoInfo * date;//date指针指向动态内存开辟的一块空间
int size;//记录当前的联系人个数
int capacity;//记录容量
};
void ContactInit(struct Contact* ps);
void ContactAdd(struct Contact* ps);
int FindByName(char name[MAX_NAME], const struct Contact* ps);
void ContactDelete(struct Contact* ps);
void ContactSearch(const struct Contact* ps);
void ContactModify(struct Contact* ps);
void ContactShow(struct Contact* ps);
int CmpByName(const void* e1, const void* e2);
void ContactSort(struct Contact* ps);
void ContactDestory(struct Contact* ps);
谢谢各位博友的支持!