一、静态创建通讯录
1、保存1000个人的信息
(1)一个人的信息包括:名字、性别、年龄、电话、住址
//声明通讯录人的信息
typedef struct PeoInfo
{
char name[20];
char sex[5];
int age;
char tele[12];//电话一般十一位
char addr[30];
}PeoInfo;
(2)保存1000个人的信息
//创建包含1000个元素的数组
PeoInfo data[1000];//存放1000个人的信息
(3)补充:为了方便后期修改常数,直接define声明常量
#define MAX 1000
#define NAME_MAX 20
#define SEX_MAX 5
#define TELE_MAX 12
#define ADDR_MAX 30
typedef struct PeoInfo
{
char name[NAME_MAX];
char sex[SEX_MAX];
int age;
char tele[TELE_MAX];//电话一般十一位
char addr[ADDR_MAX];
}PeoInfo;
typedef struct Contact
{
PeoInfo data[MAX];//创建通讯录,可以保存1000个人的信息
int sz;//记录通讯录中已经保存的信息个数
}Contact;
2、静态创建通讯录
(1)直接使用 PeoInfo 创建data[1000] 数组,存放1000个人的信息。但考虑到打印已有成员信息时要记录已有成员的个数,创建变量 sz,记录通讯录中已经保存的信息个数。为了传参方便,直接将data[1000] 与 sz 放在结构体Contact中,传参的时候只需传Contact。
typedef struct Contact
{
PeoInfo data[1000];//创建通讯录,可以保存1000个人的信息
int sz;//记录通讯录中已经保存的联系人信息个数
}Contact;
(2)在test()函数中 创建通讯录
Contact con;
3、静态初始化通讯录
(1)将sz初始化为0;
(2)将data[1000]数组中的元素初始化为0;
//初始化通讯录
void InitContact(Contact* pc)
{
memset(pc->data,0,sizeof(pc->data));
pc->sz = 0;
}
4、静态添加联系人
(1)静态添加联系人时,当sz==10001时,此时数组已满,无法再添加。所以在添加前要先判断。
if (pc->sz == MAX)
{
printf("通讯录已满,无法添加\n");
return;
}
二、动态创建通讯录相对于静态不同之处
1、定义通讯录结构体,包含三个成员。
typedef struct Contact
{
PeoInfo* data;//创建一个data结构体指针,类型是PeoInfo*。
int sz;//记录通讯录已添加的联系人数
int capacity;//记录通讯录当前最大容量
}Contact;
2、创建结构体变量
Contact con;
3、在初始化动态版本通讯录时:
(1)将sz初始化为0;
(2)将capacity初始化为3;
(3)使用malloc()开辟可以存放三个联系人信息的空间,返回值用data指针接收;
(4)data中的元素初始化为0。
注意:malloc();参数是以字节为单位,返回值是开辟的空间起始位置地址。
//初始化通讯录
void InitContact(Contact* pc)
{
pc->sz = 0;
pc->capacity=3;
//也可以#define DEFAULT_SZ 3 方便修改
// pc->capacity=DEFAULT_SZ;
pc->data=(PeoInfo *)malloc(pc->capacity*sizeof(PeoInfo));
//若开辟失败,返回NULL
if(pc->data==NULL)
{
perror("malloc");
return;
}
memset(pc->data,0,pc->capacity*sizeof(PeoInfo));
}
4、添加联系人
(1)动态添加联系人时,当sz==capacity时,此时创建的空间已满,无法再添加,需要扩容,然后再添加。
(2)扩容使用realloc函数
void* realloc (void* ptr, size_t size);
ptr 是要调整的内存地址
size 调整之后新大小,字节为单位。
返回值为调整之后的内存起始位置。
这个函数调整原内存空间大小的基础上,还会将原来内存中的数据移动到 新 的空间。
(3)扩容可能失败,所以不要直接将扩容后的返回值赋给data指针:
- 假设扩容成功,那程序没有问题
- 假设扩容失败,realloc函数将返回NULL,NULL直接被赋给data指针,那指针被置空,地址丢失,找不到之前的空间了。
- 所以借助中间值,用中间值接收返回值,若不为NULL,再将中间值赋给data。
(4)使用realloc函数、malloc函数要引头文件<stdlib.h>
//添加前的判断
if (pc->sz == pc->capacity)
{
PeoInfo* tmp=(PeoInfo*)realloc(pc->data,(pc->capacity+2)*sizeof(PeoInfo));//假设每次扩容2
if(tmp!=NULL)
{
pc->data=tmp;
}
pc-capacity+=2;//容量增加了。
}
(4)扩容不止是添加时要使用,其他功能可能也要使用,所以将扩容这个功能写成函数,使用时直接调用,更为方便。
void CheckCapacity(Contact* pc)
{
if (pc->sz == pc->capacity)
{
PeoInfo* tmp=(PeoInfo*)realloc(pc->data,(pc->capacity+2)*sizeof(PeoInfo));//假设每次扩容2
if(tmp!=NULL)
{
pc->data=tmp;
}
pc->capacity+=2;//容量增加了。
printf("增容成功\n");
}
}
5、动态申请的空间要记得释放
可以增添一个销毁通讯录的函数。
void DestroyContact(Contact* pc)
{
free(pc->data);
data=NULL;
pc->sz=0;
pc->capacity=0;
}