我们在学习结构体之后,就可以尝试去实现通讯录的制作,如果您这边对于结构体还没有太多的认识的话,请先访问这一篇文章,会有利于接下来的学习。【自定义类型】带你走进结构体、枚举、联合_小王学代码的博客-CSDN博客
目录
前言
通讯录是一个简单的程序,我们接下来用C语言来实现静态以及动态通讯录。我们先了解一下什么叫静态?
静态通讯录:通讯录能存储人员的大小是固定的,可能会浪费,可能会不够
动态通讯录:可以实现动态扩容,不够就扩容,比较节省时间和空间,更加方便
一、通讯录
首先我们应该知道,通讯录应该有那些功能
1.增删查改,都要有
2.关闭通讯录
3.排序通讯录中的人员
二、静态通讯录
动态比静态只需要修改一部分内容,我们先讲解一下静态通讯录如何制作
1.完成什么功能
图示:
2.通讯录的主干怎么写?
使用菜单的形式,在main函数外使用test函数,在test中使用do while和switch函数,实现通讯录的基本框架,具体代码如下。
代码演示:
//这边进行主要的通讯录流程操作
void menu() {
printf("***********************************************\n");
printf("****** 1.add 2.del ******\n");
printf("****** 3.search 4.change ******\n");
printf("****** 5.show 6.sort ******\n");
printf("****** 0.exit ******\n");
printf("***********************************************\n");
}
void test() {
int input = 0;
int pos = 0;
Contact pc;
//Contact pc={0};
//当然可以这样初始化,但是不一定后来初始化都这样,所以有InitContact()
InitContact(&pc);
do {
menu();
//打印选择菜单
printf("请选择:>");
scanf("%d", &input);
switch (input) {
case 1:
addContact(&pc);
break;
case 2:
delContact(&pc);
break;
case 3:
searchContact(&pc);
break;
case 4:
changeContact(&pc);
break;
case 5:
showContact(&pc);
break;
case 6:
sortContact(&pc);
break;
case 0:
printf("退出通讯录\n");
break;
default:
break;
}
} while (input);
}
int main()
{
test();
return 0;
}
3.逐步完成各项功能
初始化、增删改查,排序等功能的实现,我们放在Contact.c文件中进行实现
1.结构体的实现
代码如下:
#define MAX 100
#define NAME_MAX 20
#define SEX_MAX 5
#define ADDR_MAX 20
#define TELE_MAX 12
//下面两个define是用于动态通讯录的
#define MAX1 3 //表示第一次容积是多少
#define MAX2 2 //表示一次扩容多少
//构建通讯录所需的结构体
typedef struct PeopleInfo {
char name[NAME_MAX];//姓名
int age;//年龄
char sex[NAME_MAX];//性别
char addr[ADDR_MAX];//地址
char tele[TELE_MAX];//电话号码
}PeopleInfo;
//这是静态通讯录 就是data这个数组是固定死的MAX
typedef struct Contact {
PeopleInfo data[MAX];//表示存储的通讯录最大人员数
int sz;//表示当前Contact通讯录人员个数
}Contact;
2.初始化通讯录
代码如下:
//这是静态初始化
void InitContact(Contact* pc) {
//进行初始化的时候,我们当然可以直接
pc->sz = 0;
memset(pc->data, 0, sizeof(pc->data));
//memset 函数 这样的话,从data这个数组的地址开始 sizeof(pc->data)个字节,都赋值为0
}
使用了memset内存管理函数,对pc->data数组进行初始化都为0,sz表示的是人员个数,也为0
3.添加人员
代码如下:
//静态通讯录
void addContact(Contact* pc) {
assert(pc);//断言
if (pc->sz == MAX) { //判满,满了无法添加
printf("通讯录已满,无法添加\n");
return;
}
printf("请输入名字:>");
scanf("%s", pc->data[pc->sz].name);
printf("请输入年龄:>");
scanf("%d", &(pc->data[pc->sz].age));
printf("请输入性别:>");
scanf("%s", pc->data[pc->sz].sex);
printf("请输入地址:>");
scanf("%s", pc->data[pc->sz].addr);
printf("请输入电话:>");
scanf("%s", pc->data[pc->sz].tele);
printf("添加完成,请继续操作\n");
//添加完一个就sz++,表示有一个人员加入通讯录中
pc->sz++;
}
3.删除指定人员
代码如下:
void delContact(Contact* pc) {
assert(pc);
printf("请选择删除的目标:>");
if (pc->sz == 0) {
return;
}
//删除的话只需要找到对应的要删除的数据,比如以名字为准,先找到,然后再讲其后面的元素覆盖前面的
int pos = searchContact(pc);
//换位置
if (pos == -1) {
printf("没有查找到该成员\n");
return;
}
for (int i = pos; i < pc->sz - 1; i++) {
pc->data[i] = pc->data[i + 1];
}
pc->sz--;//直接--不用管换位置之后最后一个数字的问题
printf("删除完成\n");
}
可以删除指定姓名人员,当然可以自行做出一些改善,这是比较简单易懂的通讯录。
4.查找指定人员的信息
代码如下:
int searchContact(Contact* pc) {
assert(pc);//断言
char name[20];
int pos = -1; //pos等于-1是因为 如果找不到一样的姓名,就返回-1,表示没有
scanf("%s", name);
//查询
for (int i = 0; i < pc->sz; i++) {
if (strcmp(pc->data[i].name, name) == 0) {
pos = i; //使用strcmp函数,进行比较
}
}
return pos;
}
使用了strcmp函数,大家有不理解的可以去下面链接进行访问查看
【C语言进阶】带你轻松玩转字符、字符串函数_小王学代码的博客-CSDN博客
5.改变指定人员的信息
代码如下:
int searchContact(Contact* pc) {
assert(pc);
char name[20];
int pos = -1;
scanf("%s", name);
//查询
for (int i = 0; i < pc->sz; i++) {
if (strcmp(pc->data[i].name, name) == 0) {
pos = i;
}
}
return pos;
}
//协助查找函数被,找到被查改人员在data数组的下标位置,再进行修改
void changeContact(Contact* pc) {
assert(pc);
//先找到
int pos = searchContact(pc);
printf("请输入名字:>");
scanf("%s", pc->data[pos].name);
printf("请输入年龄:>");
scanf("%d", &(pc->data[pos].age));
printf("请输入性别:>");
scanf("%s", pc->data[pos].sex);
printf("请输入地址:>");
scanf("%s", pc->data[pos].addr);
printf("请输入电话:>");
scanf("%s", pc->data[pos].tele);
printf("更改完成, 请继续操作\n");
}
协助于查找函数,找到被查改人员在data数组的下标位置,再进行修改。
6.打印通讯录人员信息
代码如下:
void showContact(Contact* pc) {
assert(pc);
if (pc->sz == 0) {
return;
}//可以有可无
printf("%-20s\t%-5s\t%-5s\t%-20s\t%-12s\n", "姓名", "年龄", "性别", "地址", "电话");
for (int i = 0; i < pc->sz; i++) {
printf("%-20s\t%-5d\t%-5s\t%-20s\t%-12s\n", pc->data[i].name, pc->data[i].age, pc->data[i].sex, pc->data[i].addr, pc->data[i].tele);
}
printf("打印完成\n");
}
对于printf中的 %-20s \ t 进行解释,-表示左对齐,20表示这个字符串20个位置,保持左对齐打印,\t 是字表符,是为了更加美观,使得各项数据对齐
7.排序通讯录
排序的依据有很多,我们这里是按照姓名大小排序,使用函数strcmp,实际上也可以使用qsort函数进行排序
代码如下:
void sortContact(Contact* pc) {
assert(pc);
if (pc->sz == 0) {
printf("通讯录中暂无元素\n");
return;
}
Contact s = { 0 };
for (int i = 0; i < pc->sz-1; i++) {
for (int j = i; j < pc->sz-1; j++) {
if (strcmp(pc->data[j].name, pc->data[j + 1].name)==1) {
s.data[j] = pc->data[j];
pc->data[j] = pc->data[j + 1];
pc->data[j + 1] = s.data[j];
}
}
}
}
使用的是strcmp函数结合冒泡排序,这样还可以使用qsort函数,使用方法可以参考
【C语言进阶】指针的进阶(下)_小王学代码的博客-CSDN博客
qsort函数代码如下:
int compare(const void* e1, const void* e2) {
return *((int*)e1) - *((int*)e2);
}
void sort(Contact*pc) {
qsort(pc->data, pc->sz, sizeof(pc->data[0]), compare);
}
三、动态通讯录
动态通讯录相较于静态通讯录主要在结构体、初始化、增加成员的时候进行了改动
1.改动结构体
代码如下:
//构建通讯录所需的结构体
typedef struct PeopleInfo {
char name[NAME_MAX];//姓名
int age;//年龄
char sex[NAME_MAX];//性别
char addr[ADDR_MAX];//地址
char tele[TELE_MAX];//电话号码
}PeopleInfo;
//实现动态通讯录
typedef struct Contact {
PeopleInfo *data;//表示存储的通讯录最大人员数
int sz;//表示当前Contact通讯录人员个数
int capacity; //表示当前容量 作为扩容的依据
}Contact;
讲data数组变成指针的形式,不再固定通讯录容量大小,可以适当扩容
2.改动初始化
使用malloc函数进行内存申请,初始化
代码如下:
//这是动态通讯录的初始化
void InitContact(Contact* pc) {
//进行初始化的时候,我们当然可以直接
assert(pc);//断言
pc->sz = 0;
PeopleInfo *ptr=(PeopleInfo*)calloc(MAX1,sizeof(PeopleInfo));
if (ptr == NULL) {
perror("malloc::data");
return;
}
pc->data = ptr;
pc->capacity=MAX1;
}
对data空间进行申请,MAX1 表示的是初始的时候data容量大小
3.改动添加人员函数
实现扩容机制,如果sz和capacity相等,表示人员个数和容量相等,不能再添加人员了,这个时候需要check_capacity函数进行检查是否满,并扩容
代码如下:
//动态通讯录
void check_capacity(Contact* pc) {
PeopleInfo* ptr = (PeopleInfo*)realloc(pc->data, sizeof(PeopleInfo)*(pc->capacity+MAX2));
if (ptr == NULL) {
perror("check_capacity");
return;
}
pc->data = ptr;
pc->capacity = pc->capacity + MAX2;
}
void addContact(Contact* pc) {
assert(pc);
if (pc->sz == pc->capacity) {
//使用realloc函数 进行扩容
check_capacity(pc);
printf("扩容完成\n");
}
printf("请输入名字:>");
scanf("%s", pc->data[pc->sz].name);
printf("请输入年龄:>");
scanf("%d", &(pc->data[pc->sz].age));
printf("请输入性别:>");
scanf("%s", pc->data[pc->sz].sex);
printf("请输入地址:>");
scanf("%s", pc->data[pc->sz].addr);
printf("请输入电话:>");
scanf("%s", pc->data[pc->sz].tele);
printf("添加完成,请继续操作\n");
pc->sz++;
}
使用了realloc函数进行扩容处理
四、整体通讯录代码
1.静态通讯录
都有三种文件,test.c Contact.c Contact.h,分别是框架,实现,头文件声明,三个作用
1.test.c文件
#define _CRT_SECURE_NO_WARNINGS
#include"Contact.h"
//这边进行主要的通讯录流程操作
void menu() {
printf("***********************************************\n");
printf("****** 1.add 2.del ******\n");
printf("****** 3.search 4.change ******\n");
printf("****** 5.show 6.sort ******\n");
printf("****** 0.exit ******\n");
printf("***********************************************\n");
}
void test() {
//打印选择菜单
int input = 0;
int pos = 0;
Contact pc;
//Contact pc={0};
//当然可以这样初始化,但是不一定后来初始化都这样,所以有InitContact()
InitContact(&pc);
do {
menu();
printf("请选择:>");
scanf("%d", &input);
switch (input) {
case 1:
addContact(&pc);
break;
case 2:
delContact(&pc);
break;
case 3:
pos = searchContact(&pc);
if (pos == -1) {
printf("没有查找到该成员\n");
}
else {
printf("%-20s\t%-5d\t%-5s\t%-20s\t%-12s\n", pc.data[pos].name, pc.data[pos].age, pc.data[pos].sex, pc.data[pos].addr, pc.data[pos].tele);
}
break;
case 4:
changeContact(&pc);
break;
case 5:
showContact(&pc);
break;
case 6:
sort(&pc);
break;
case 0:
printf("退出通讯录\n");
break;
default:
break;
}
} while (input);
}
int main()
{
test();
return 0;
}
2.Contact.c
#define _CRT_SECURE_NO_WARNINGS
#include"Contact.h"
//用来实现头文件的代码
//
这是静态初始化
void InitContact(Contact* pc) {
//进行初始化的时候,我们当然可以直接
pc->sz = 0;
memset(pc->data, 0, sizeof(pc->data));
//memset 函数 这样的话,从data这个数组的地址开始 sizeof(pc->data)个字节,都赋值为0
}
静态通讯录
void addContact(Contact* pc) {
assert(pc);
if (pc->sz == MAX) {
printf("通讯录已满,无法添加\n");
return;
}
printf("请输入名字:>");
scanf("%s", pc->data[pc->sz].name);
printf("请输入年龄:>");
scanf("%d", &(pc->data[pc->sz].age));
printf("请输入性别:>");
scanf("%s", pc->data[pc->sz].sex);
printf("请输入地址:>");
scanf("%s", pc->data[pc->sz].addr);
printf("请输入电话:>");
scanf("%s", pc->data[pc->sz].tele);
printf("添加完成,请继续操作\n");
pc->sz++;
}
void delContact(Contact* pc) {
assert(pc);
printf("请选择删除的目标:>");
if (pc->sz == 0) {
return;
}
//删除的话只需要找到对应的要删除的数据,比如以名字为准,先找到,然后再讲其后面的元素覆盖前面的
int pos = searchContact(pc);
//换位置
if (pos == -1) {
printf("没有查找到该成员\n");
return;
}
for (int i = pos; i < pc->sz - 1; i++) {
pc->data[i] = pc->data[i + 1];
}
pc->sz--;//直接--不用管换位置之后最后一个数字的问题
printf("删除完成\n");
}
int searchContact(Contact* pc) {
assert(pc);
char name[20];
int pos = -1;
scanf("%s", name);
//查询
for (int i = 0; i < pc->sz; i++) {
if (strcmp(pc->data[i].name, name) == 0) {
pos = i;
}
}
return pos;
}
void showContact(Contact* pc) {
assert(pc);
if (pc->sz == 0) {
return;
}//可以有可无
printf("%-20s\t%-5s\t%-5s\t%-20s\t%-12s\n", "姓名", "年龄", "性别", "地址", "电话");
for (int i = 0; i < pc->sz; i++) {
printf("%-20s\t%-5d\t%-5s\t%-20s\t%-12s\n", pc->data[i].name, pc->data[i].age, pc->data[i].sex, pc->data[i].addr, pc->data[i].tele);
}
printf("打印完成\n");
}
void changeContact(Contact* pc) {
assert(pc);
//先找到
int pos = searchContact(pc);
printf("请输入名字:>");
scanf("%s", pc->data[pos].name);
printf("请输入年龄:>");
scanf("%d", &(pc->data[pos].age));
printf("请输入性别:>");
scanf("%s", pc->data[pos].sex);
printf("请输入地址:>");
scanf("%s", pc->data[pos].addr);
printf("请输入电话:>");
scanf("%s", pc->data[pos].tele);
printf("更改完成, 请继续操作\n");
}
void sortContact(Contact* pc) {
assert(pc);
if (pc->sz == 0) {
printf("通讯录中暂无元素\n");
return;
}
Contact s;
InitContact(&s);
for (int i = 0; i < pc->sz-1; i++) {
for (int j = 0; j < pc->sz-1-i; j++) {
if (strcmp(pc->data[j].name, pc->data[j + 1].name)==1) {
s.data[j] = pc->data[j];
pc->data[j] = pc->data[j + 1];
pc->data[j + 1] = s.data[j];
}
}
}
}
int compare(const void* e1, const void* e2) {
return *((int*)e1) - *((int*)e2);
}
void sort(Contact*pc) {
qsort(pc->data, pc->sz, sizeof(pc->data[0]), compare);
}
3.Contact.h
#define _CRT_SECURE_NO_WARNINGS
//Contact 实现通讯录 头文件
#include<stdio.h>
#include<string.h>
#include<assert.h>
#include<malloc.h>
#include<stdlib.h>
#include<search.h>
#define MAX 100
#define NAME_MAX 20
#define SEX_MAX 5
#define ADDR_MAX 20
#define TELE_MAX 12
//下面两个define是用于动态通讯录的
#define MAX1 3 //表示第一次容积是多少
#define MAX2 2 //表示一次扩容多少
//构建通讯录所需的结构体
typedef struct PeopleInfo {
char name[NAME_MAX];//姓名
int age;//年龄
char sex[NAME_MAX];//性别
char addr[ADDR_MAX];//地址
char tele[TELE_MAX];//电话号码
}PeopleInfo;
//这是静态通讯录 就是data这个数组是固定死的MAX
typedef struct Contact {
PeopleInfo data[MAX];//表示存储的通讯录最大人员数
int sz;//表示当前Contact通讯录人员个数
}Contact;
//初始化通讯录
void InitContact(Contact* pc);
//添加通讯录的信息
void addContact(Contact* pc);
//删除通讯录中的信息
void delContact(Contact* pc);
//查找通讯录成员信息
int searchContact(Contact* pc);
//打印
void showContact(Contact* pc);
//改变指定元素
void changeContact(Contact* pc);
//排序,按照名字排序
void sortContact(Contact* pc);
2.动态通讯录
1.test.c
#define _CRT_SECURE_NO_WARNINGS
#include"Contact.h"
//这边进行主要的通讯录流程操作
void menu() {
printf("***********************************************\n");
printf("****** 1.add 2.del ******\n");
printf("****** 3.search 4.change ******\n");
printf("****** 5.show 6.sort ******\n");
printf("****** 0.exit ******\n");
printf("***********************************************\n");
}
void test() {
//打印选择菜单
int input = 0;
int pos = 0;
Contact pc;
//Contact pc={0};
//当然可以这样初始化,但是不一定后来初始化都这样,所以有InitContact()
InitContact(&pc);
do {
menu();
printf("请选择:>");
scanf("%d", &input);
switch (input) {
case 1:
addContact(&pc);
break;
case 2:
delContact(&pc);
break;
case 3:
pos = searchContact(&pc);
if (pos == -1) {
printf("没有查找到该成员\n");
}
else {
printf("%-20s\t%-5d\t%-5s\t%-20s\t%-12s\n", pc.data[pos].name, pc.data[pos].age, pc.data[pos].sex, pc.data[pos].addr, pc.data[pos].tele);
}
break;
case 4:
changeContact(&pc);
break;
case 5:
showContact(&pc);
break;
case 6:
sort(&pc);
break;
case 0:
printf("退出通讯录\n");
free(pc.data);
break;
default:
break;
}
} while (input);
}
int main()
{
test();
return 0;
}
2.Contact.c
#define _CRT_SECURE_NO_WARNINGS
#include"Contact.h"
//用来实现头文件的代码
//
//这是动态通讯录的初始化
void InitContact(Contact* pc) {
//进行初始化的时候,我们当然可以直接
assert(pc);//断言
pc->sz = 0;
PeopleInfo *ptr=(PeopleInfo*)calloc(MAX1,sizeof(PeopleInfo));
if (ptr == NULL) {
perror("malloc::data");
return;
}
pc->data = ptr;
pc->capacity=MAX1;
}
//动态通讯录
void check_capacity(Contact* pc) {
PeopleInfo* ptr = (PeopleInfo*)realloc(pc->data, sizeof(PeopleInfo)*(pc->capacity+MAX2));
if (ptr == NULL) {
perror("check_capacity");
return;
}
pc->data = ptr;
pc->capacity = pc->capacity + MAX2;
}
void addContact(Contact* pc) {
assert(pc);
if (pc->sz == pc->capacity) {
//使用realloc函数 进行扩容
check_capacity(pc);
printf("扩容完成\n");
}
printf("请输入名字:>");
scanf("%s", pc->data[pc->sz].name);
printf("请输入年龄:>");
scanf("%d", &(pc->data[pc->sz].age));
printf("请输入性别:>");
scanf("%s", pc->data[pc->sz].sex);
printf("请输入地址:>");
scanf("%s", pc->data[pc->sz].addr);
printf("请输入电话:>");
scanf("%s", pc->data[pc->sz].tele);
printf("添加完成,请继续操作\n");
pc->sz++;
}
void delContact(Contact* pc) {
assert(pc);
printf("请选择删除的目标:>");
if (pc->sz == 0) {
return;
}
//删除的话只需要找到对应的要删除的数据,比如以名字为准,先找到,然后再讲其后面的元素覆盖前面的
int pos = searchContact(pc);
//换位置
if (pos == -1) {
printf("没有查找到该成员\n");
return;
}
for (int i = pos; i < pc->sz - 1; i++) {
pc->data[i] = pc->data[i + 1];
}
pc->sz--;//直接--不用管换位置之后最后一个数字的问题
printf("删除完成\n");
}
int searchContact(Contact* pc) {
assert(pc);
char name[20];
int pos = -1;
scanf("%s", name);
//查询
for (int i = 0; i < pc->sz; i++) {
if (strcmp(pc->data[i].name, name) == 0) {
pos = i;
}
}
return pos;
}
void showContact(Contact* pc) {
assert(pc);
if (pc->sz == 0) {
return;
}//可以有可无
printf("%-20s\t%-5s\t%-5s\t%-20s\t%-12s\n", "姓名", "年龄", "性别", "地址", "电话");
for (int i = 0; i < pc->sz; i++) {
printf("%-20s\t%-5d\t%-5s\t%-20s\t%-12s\n", pc->data[i].name, pc->data[i].age, pc->data[i].sex, pc->data[i].addr, pc->data[i].tele);
}
printf("打印完成\n");
}
void changeContact(Contact* pc) {
assert(pc);
//先找到
int pos = searchContact(pc);
printf("请输入名字:>");
scanf("%s", pc->data[pos].name);
printf("请输入年龄:>");
scanf("%d", &(pc->data[pos].age));
printf("请输入性别:>");
scanf("%s", pc->data[pos].sex);
printf("请输入地址:>");
scanf("%s", pc->data[pos].addr);
printf("请输入电话:>");
scanf("%s", pc->data[pos].tele);
printf("更改完成, 请继续操作\n");
}
void sortContact(Contact* pc) {
assert(pc);
if (pc->sz == 0) {
printf("通讯录中暂无元素\n");
return;
}
Contact s;
InitContact(&s);
for (int i = 0; i < pc->sz-1; i++) {
for (int j = 0; j < pc->sz-1-i; j++) {
if (strcmp(pc->data[j].name, pc->data[j + 1].name)==1) {
s.data[j] = pc->data[j];
pc->data[j] = pc->data[j + 1];
pc->data[j + 1] = s.data[j];
}
}
}
}
int compare(const void* e1, const void* e2) {
return *((int*)e1) - *((int*)e2);
}
void sort(Contact*pc) {
qsort(pc->data, pc->sz, sizeof(pc->data[0]), compare);
}
3.Contact.h
#define _CRT_SECURE_NO_WARNINGS
//Contact 实现通讯录 头文件
#include<stdio.h>
#include<string.h>
#include<assert.h>
#include<malloc.h>
#include<stdlib.h>
#include<search.h>
#define MAX 100
#define NAME_MAX 20
#define SEX_MAX 5
#define ADDR_MAX 20
#define TELE_MAX 12
//下面两个define是用于动态通讯录的
#define MAX1 3 //表示第一次容积是多少
#define MAX2 2 //表示一次扩容多少
//构建通讯录所需的结构体
typedef struct PeopleInfo {
char name[NAME_MAX];//姓名
int age;//年龄
char sex[NAME_MAX];//性别
char addr[ADDR_MAX];//地址
char tele[TELE_MAX];//电话号码
}PeopleInfo;
//实现动态通讯录
typedef struct Contact {
PeopleInfo *data;//表示存储的通讯录最大人员数
int sz;//表示当前Contact通讯录人员个数
int capacity; //表示当前容量 作为扩容的依据
}Contact;
//初始化通讯录
void InitContact(Contact* pc);
//添加通讯录的信息
void addContact(Contact* pc);
//删除通讯录中的信息
void delContact(Contact* pc);
//查找通讯录成员信息
int searchContact(Contact* pc);
//打印
void showContact(Contact* pc);
//改变指定元素
void changeContact(Contact* pc);
//排序,按照名字排序
void sortContact(Contact* pc);
总结
静态通讯录和动态通讯录都是比较简单好实现的,静态通讯录是固定的数组的形式储存成员,不确定成员个数的情况下,可能会浪费空间,也可能不够用。但是动态通讯录通过不断扩容,更好的解决了这个空间的事情,不会造成太多浪费。
动态,是依靠malloc、free、calloc、realloc这些函数进行申请空间,进行维护不断扩容的,下一章节,我们来一起细致的去讲解一下这四种函数的使用和区别