C语言实现可增容动态通讯录详细过程
创建可自动扩容的通讯录
这里我们想实现通讯录自动扩容,不够了能扩大内存,变得稍微有点智能,就不得不用到开辟内存的函数malloc和realloc,这两个函数又和free离不开关系
所以这里我给大家简单的介绍一下这三个库函数
malloc:这个函数向内存申请一块连续可用的空间,并返回指向这块空间的指针
void *malloc( size_t size );
如果开辟成功,则返回一个指向开辟好空间的指针。
如果开辟失败,则返回一个NULL指针,因此malloc的返回值一定要做检查。
返回值的类型是 void* ,所以malloc函数并不知道开辟空间的类型,具体在使用的时候使用者自己
来决定。
如果参数 size 为0,malloc的行为是标准是未定义的,取决于编译器
这里给大家简单的演示一下:
int main() { int arr[5] = { 0 }; int* ptr = NULL; ptr = (int*)malloc(5 * sizeof(int));//开辟5个大小为int整型的空间给ptr //判断是否开辟成功 if (ptr == NULL) { perror(malloc);//打印错误信息 return; } free(ptr);//释放内存 ptr = NULL;//消除野指针问题 return 0; }
realloc:realloc函数的出现让动态内存管理更加灵活。
有时会我们发现过去申请的空间太小了,有时我们又会觉得申请的空间过大了,那为了合理的时使用内存,我们一定会对内存的大小做灵活的调整。那 realloc 函数就可以做到对动态开辟内存大小的调整
void* realloc (void* ptr, size_t size);
ptr 是要调整的内存地址
size 调整之后新大小
返回值为调整之后的内存起始位置。
这个函数调整原内存空间大小的基础上,还会将原来内存中的数据移动到新的空间
值得我们注意的是这个函数的开辟内存有两种情况:
情况1
当原有空间之后有足够大的空间的时候,要扩展内存就直接原有内存之后直接追加空间,原来空间的数据不发生变化。
情况2
当原有空间之后没有足够大的空间时候,原有空间之后没有足够多的空间时,扩展的方法是:在堆空间上另找一个合适大小
的连续空间来使用。这样函数返回的是一个新的内存地址
free:用来释放内存的,这个函数是搭配开辟内存的函数使用且非常关键,如果开辟了内存不及时释放的话会造成内存释放等严重后果,若重复释放也会有不良影响,所以需要我们注意。
当我们了解了上面三个函数过后我们来试着建立一个可扩容的通讯录
这里我们先创建一个结构体用来存放用户的信息
//在这里进行初始化赋值,若以后有变只需在这一个地方改变 #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;//可以存放人的信息(可增长) int sz;//记录通讯中已经保存的信息个数 int capacity;//记录通讯录当前的最大容量 }Contact;
当数量大于3时我们就应该扩容并初始化,具体实现
//通讯录初始状态的容量大小 #define DEFAULT_SZ 3 void InitContact(Contact* pc) { assert(pc); pc->sz = 0; pc->capacity = DEFAULT_SZ; pc->data = (PeoInfo*)malloc(pc->capacity * sizeof(PeoInfo)); if (pc->data == NULL) { perror("InitContact::malloc"); return; } memset(pc->data, 0, pc->capacity * sizeof(PeoInfo)); } void CheckCapacity(Contact* pc) { //增容(当用户等于最大容量时) if (pc->sz == pc->capacity) { //开辟两个大小为PeoInfo的内存并且强制类型转换为PeoInfo*类型放在tmp地址处 PeoInfo* tmp = (PeoInfo*)realloc(pc->data, (pc->capacity + 2) * sizeof(PeoInfo)); if (tmp != NULL) { pc->data = tmp;//将tmp地址给到pc->data达到连续存放的目的 } else { perror("CheckCapacity::realloc");//开辟失败打印错误信息 return; } pc->capacity += 2;//开辟成功后及时更新最大容量 printf("增容成功\n"); } }
添加用户信息
实现:
void AddContact(Contact* pc) { assert(pc); //动态的版本 CheckCapacity(pc);//输入前看是否需要扩容 //录入信息 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].tele); printf("请输入地址:>"); scanf("%s", pc->data[pc->sz].addr); pc->sz++; printf("添加成功\n"); }
删除用户信息
//找到了返回下标 //找不到返回-1 int FindByName(const Contact* pc, char name[]) { assert(pc); int i = 0; for (i = 0; i < pc->sz; i++) { if (0 == strcmp(pc->data[i].name, name)) { return i; } } return -1; } //删之前需要先查找是否有这个用户 void DelContact(Contact* pc) { assert(pc); if (pc->sz == 0) { printf("通讯录已空,无法删除\n"); return; } //删除 //1. 找到 char name[NAME_MAX] = { 0 }; printf("请输入要删除人的名字:>"); scanf("%s", name); int pos = FindByName(pc, name);//通过函数查找 if (pos == -1) { printf("要删除的人不存在\n"); return; } //2. 删除 int j = 0; for (j = pos; j < pc->sz - 1; j++) { pc->data[j] = pc->data[j + 1]; } pc->sz--; printf("删除成功\n"); }
查找联系人
int FindByName(const Contact* pc, char name[]) { assert(pc); int i = 0; for (i = 0; i < pc->sz; i++) { if (0 == strcmp(pc->data[i].name, name)) { return i; } } return -1; } void SearchContact(const Contact* pc) { char name[NAME_MAX] = { 0 }; printf("请输入要查找人的名字:>"); scanf("%s", name); int pos = FindByName(pc, name); if (pos == -1) { printf("要查找的人不存在\n"); return; } printf("%-20s %-5s %-5s %-12s %-30s\n", "姓名", "年龄", "性别", "电话", "地址"); printf("%-20s %-5d %-5s %-12s %-30s\n", pc->data[pos].name, pc->data[pos].age, pc->data[pos].sex, pc->data[pos].tele, pc->data[pos].addr); }
修改用户信息
//修改信息 void ModifyContact(Contact* pc) { //首先先找到要修改的人 int input = 0; char name[NAME_MAX] = { 0 }; printf("请输入要查找人的名字:>"); scanf("%s", name); int pos = FindByName(pc, name); if (pos == -1) { printf("要查找的人不存在\n"); return; } printf("%-20s %-5s %-5s %-12s %-30s\n", "姓名", "年龄", "性别", "电话", "地址"); printf("%-20s %-5d %-5s %-12s %-30s\n", pc->data[pos].name, pc->data[pos].age, pc->data[pos].sex, pc->data[pos].tele, pc->data[pos].addr); printf("请选择你要修改的信息:\n"); //用switch语句可以实现只改某一项的信息 do { printf("0.修改完毕 1.姓名 2.年龄 3.性别 4.电话 5.地址\n"); scanf("%d", &input); switch (input) { case 1: printf("请输入修改的名字:>"); scanf("%s", pc->data[pos].name); break; case 2: printf("请输入修改的年龄:>"); scanf("%d", &(pc->data[pos].age));//注意取地址 break; case 3: printf("请输入修改的性别:>"); scanf("%s", pc->data[pos].sex); break; case 4: printf("请输入修改的电话:>"); scanf("%s", pc->data[pos].tele); break; case 5: printf("请输入修改的地址:>"); scanf("%s", pc->data[pos].addr); break; } } while (input); printf("修改成功\n"); }
以名字将用户排序
//以姓名排序(A~Z的顺序) void SortContact(Contact* pc) { int i = 0; for (i = 0; i < pc->sz-1; i++) { int ret = strcmp(pc->data[i].name, pc->data[i + 1].name); if (ret > 0) { PeoInfo tmp; tmp = pc->data[i]; pc->data[i] = pc->data[i + 1]; pc->data[i + 1] = tmp; } } printf("排序成功\n"); }
销毁通讯录
当结束时销毁通讯录,释放内存,避免出现内存泄漏等问题
void DestroyContact(Contact* pc) { free(pc->data); pc->data = NULL; pc->capacity = 0; pc->sz = 0; printf("销毁成功\n"); }
这里只展示了功能函数以及我认为一些需要注意的地方,若想看完整版可以去下面的链接看看哦