【C语言】通讯录(动态增长版本)

文章介绍了如何使用C语言改进通讯录程序,通过动态内存管理实现通讯录的动态增长,避免空间浪费。在初始化时设置较小的默认空间,随着联系人数量增加,使用realloc函数进行扩容。同时,文章强调了在通讯录销毁时释放内存以防止内存泄漏的重要性。
摘要由CSDN通过智能技术生成
作者:热爱编程的小y
专栏:C语言
格言:能打败你的只能是明天的你

上一次写了一篇关于通讯录的博客,那只是初级版本,需要完善的地方还很多,今天我们来进行修改,让之成为一个可以动态增长的版本。

博客链接在这-->【C语言】详解通讯录(初级版本)

思路

在原来的版本下,通讯录的空间是固定的,即含有能存放100个联系人的空间,但我们经常会用不完,即通讯录经常存不满,导致空间的浪费。

那么我们就可以设定初始空间为3,存满3个联系人后扩容2个空间,之后再存满再扩容,这样就大大减少了空间浪费的可能性。(初始空间的大小以及每次扩容的大小完全由自己决定,前面这样设定是为了调试的方便)

要实现上述想法就要用到动态内存管理的知识。

详情请看这篇博客-->动态内存管理

实现

为了让代码的数值方便修改,我们把初始空间大小和扩容大小定义为两个宏:


#define DEFAULT_SIZE 3//初始空间大小
#define INC_SIZE 2//每次扩容的空间大小

我们在定义通讯录的时候,要新增一个变量来表示当前通讯录的最大容量:


//定义通讯录
typedef struct Contact
{
    PeoInfo* peo;//存放联系人的空间
    int sz;//当前存放联系人的数量
    int capacity;//当前通讯录最大容量
}Contact;

初始化通讯录时,我们用calloc函数给通讯录开辟空间:


//初始化
void InitContact(Contact* pc)
{
    assert(pc);//断言,确保指针有效
    pc->sz = 0;
    PeoInfo* ptr = (PeoInfo*)calloc(DEFAULT_SIZE, sizeof(PeoInfo));//开辟空间
    if (ptr == NULL)
    {
        perror("InitContact::calloc");//空间开辟失败,打印原因
    }
    pc->peo = ptr;
    pc->capacity = DEFAULT_SIZE;
}

之后每次增加联系人的时候都需要进行一个是否扩容的判断,就是让capacity(最大容量)与sz(当前存放数量)进行比较即可,增容通过realloc函数实现。

我们把这个增容过程用一个函数进行分装:


//判断是否增容
void check_capacity(Contact* pc)
{
    assert(pc);
    if (pc->sz == pc->capacity)
    {
        PeoInfo* ptr = (PeoInfo *) realloc(pc->peo, (pc->capacity + INC_SIZE) * sizeof(PeoInfo));
        //增容失败
        if (ptr == NULL)
        {
            perror("check_capacity::realloc");
            return;
        }
        //增容成功
        pc->peo = ptr;
        pc->capacity += INC_SIZE;
    }
}

写到了这一步,通讯录的动态增长优化就已经实现了,但是还可以进行另一个小优化,同样是用动态内存管理的知识来实现。

我们在结束通讯录的使用时,应该要对通讯录进行销毁,把它的空间释放掉,不然会出现内存泄漏的可能性,这里我们用free函数进行释放即可:


//销毁
void Destroy(Contact* pc)
{
    free(pc->peo);
    pc->peo = NULL;
    pc->capacity = 0;
    pc->sz = 0;
    pc = NULL;
    return;
}

这样就用动态增长的方式优化完成啦

下面附上优化后的完整代码:


//contact.h
#pragma once
#define MAX_NAME 20//便于修改数值
#define MAX_SEX 5
#define MAX_ADDR 30
#define MAX_TELE 12
#define DEFAULT_SIZE 3
#define INC_SIZE 2

#include<stdio.h>
#include<string.h>
#include<assert.h>
#include<stdlib.h>

//联系人信息
typedef struct PeoInfo
{
    char name[MAX_NAME];
    int age;
    char sex[MAX_SEX];
    char addr[MAX_ADDR];
    char tele[MAX_TELE];
}PeoInfo;

//定义通讯录
typedef struct Contact
{
    PeoInfo* peo;//存放联系人的空间
    int sz;//当前存放联系人的数量
    int capacity;//当前通讯录最大容量
}Contact;

//初始化通讯录
void InitContact(Contact* pc);

//打印菜单
void Menu();

//1. 添加联系人
void Add_Contacts(Contact* pc);

//2. 删除联系人
void Delete_Contacts(Contact* pc);

//3. 查找联系人
void Search_Contacts(const Contact* pc);

//4. 修改联系人
void Revise_Contacts(Contact* pc);

//5. 显示联系人
void Display_Contacts(const Contact* pc);

//6. 按名字排序联系人
void Sort_Contacts(Contact* pc);

//0. 销毁内存
void Destroy(Contact* pc);

//contact.c
#define _CRT_SECURE_NO_WARNINGS 1
#include"contacts.h"

//初始化
void InitContact(Contact* pc)
{
    assert(pc);
    pc->sz = 0;
    PeoInfo* ptr = (PeoInfo*)calloc(DEFAULT_SIZE, sizeof(PeoInfo));
    if (ptr == NULL)
    {
        perror("InitContact::calloc");
    }
    pc->peo = ptr;
    pc->capacity = DEFAULT_SIZE;
}

//判断是否增容
void check_capacity(Contact* pc)
{
    assert(pc);
    if (pc->sz == pc->capacity)
    {
        PeoInfo* ptr = (PeoInfo *) realloc(pc->peo, (pc->capacity + INC_SIZE) * sizeof(PeoInfo));
        //增容失败
        if (ptr == NULL)
        {
            perror("check_capacity::realloc");
            return;
        }
        //增容成功
        pc->peo = ptr;
        pc->capacity += INC_SIZE;
    }
}

//增
void Add_Contacts(Contact* pc)
{
    if (pc->sz == 100)
    {
        printf("通讯录已满,无法添加");
        return;
    }
    check_capacity(pc);//是否增容
    printf("输入姓名:");
    scanf("%s", pc->peo[pc->sz].name);
    printf("输入年龄:");
    scanf("%d", &(pc->peo[pc->sz].age));
    printf("输入性别:");
    scanf("%s", pc->peo[pc->sz].sex);
    printf("输入住址:");
    scanf("%s", pc->peo[pc->sz].addr);
    printf("输入号码:");
    scanf("%s", pc->peo[pc->sz].tele);
    pc->sz++;
    return;
}

//删
void Delete_Contacts(Contact* pc)
{
    char name[MAX_NAME] = {"\0"};
    printf("请输入要删除的联系人:");
    scanf("%s", name);
    int del = 0;
    for (int i = 0; i < pc->sz-1; i++)
    {
        if (strcmp(pc->peo[i].name, name) == 0)
        {
            del = i;
            break;
        }
    }
    for (int i = del; i < pc->sz - 1; i++)
    {
        pc->peo[i] = pc->peo[i+1];
    }
    pc->sz--;
    printf("删除成功\n");
    return;
}

//查
void Search_Contacts(const Contact* pc)
{
    char name[MAX_NAME] = { "\0" };
    printf("请输入要查找的联系人:");
    scanf("%s", name);
    int ser=0;
    for (int i = 0; i < pc->sz - 1; i++)
    {
        if (strcmp(pc->peo[i].name, name) == 0)
        {
            ser = i;
            break;
        }
    }
    printf("%-20s\t%-4s\t%-5s\t%-20s\t%-12s\t\n", "名字", "年龄", "性别", "住址", "电话");
    printf("%-20s\t%-4d\t%-5s\t%-20s\t%-12s\t\n", pc->peo[ser].name,
        pc->peo[ser].age,
        pc->peo[ser].sex,
        pc->peo[ser].addr,
        pc->peo[ser].tele);
    return;
}

//改
void Revise_Contacts(Contact* pc)
{
    char name[MAX_NAME] = { "\0" };
    printf("请输入要修改的联系人:");
    scanf("%s", name);
    int rev;
    for (int i = 0; i < pc->sz - 1; i++)
    {
        if (strcmp(pc->peo[i].name, name) == 0)
        {
            rev = i;
            break;
        }
    }
    printf("输入修改后的内容:\n");
    printf("输入姓名:");
    scanf("%s", pc->peo[rev].name);
    printf("输入年龄:");
    scanf("%d", &(pc->peo[rev].age));
    printf("输入性别:");
    scanf("%s", pc->peo[rev].sex);
    printf("输入住址:");
    scanf("%s", pc->peo[rev].addr);
    printf("输入号码:");
    scanf("%s", pc->peo[rev].tele);
    printf("修改成功\n");
    return;
}

//显示
void Display_Contacts(const Contact* pc)
{
    printf("%-20s\t%-4s\t%-5s\t%-20s\t%-12s\t\n", "名字", "年龄", "性别", "住址", "电话");
    int i = 0;
    for (i = 0; i < pc->sz; i++)
    {
        printf("%-20s\t%-4d\t%-5s\t%-20s\t%-12s\t\n", pc->peo[i].name, 
            pc->peo[i].age, 
            pc->peo[i].sex, 
            pc->peo[i].addr, 
            pc->peo[i].tele);
    }
}

//排序
void Sort_Contacts(Contact* pc)
{
    int i = 0;
    int j = 0;
    for (i = 0; i < pc->sz - 1; i++)
    {
        for (j = 0; j < pc->sz - i - 1; j++)
        {
            if (strcmp(pc->peo[j].name, (pc->peo[j + 1]).name) > 0)
            {
                PeoInfo tmp;
                tmp = pc->peo[j];
                pc->peo[j] = pc->peo[j + 1];
                pc->peo[j + 1] = tmp;
            }
        }
    }
    printf("排序成功\n");
    return;
}

//销毁
void Destroy(Contact* pc)
{
    free(pc->peo);
    pc->peo = NULL;
    pc->capacity = 0;
    pc->sz = 0;
    pc = NULL;
    return;
}

//test.c
#define _CRT_SECURE_NO_WARNINGS 1
#include"contacts.h"
void Menu()
{
    printf("***********************************\n");
    printf("**    1.add          2.delete    **\n");
    printf("**    3.search       4.revise    **\n");
    printf("**    5.display      6.sort      **\n");
    printf("**    0.exit                     **\n");
    printf("***********************************\n");
    return;
}

int main()
{
    int choice = 0;
    Contact con;    //创建通讯录
    InitContact(&con);    //初始化通讯录
    while (1)
    {
        Menu();    //打印菜单
        printf("选择要进行的操作:");
        scanf("%d", &choice);
        switch (choice) {
        case 1:
            Add_Contacts(&con);
            break;
        case 2:
            Delete_Contacts(&con);
            break;
        case 3:
            Search_Contacts(&con);
            break;
        case 4:
            Revise_Contacts(&con);
            break;
        case 5:
            Display_Contacts(&con);
            break;
        case 6:
            Sort_Contacts(&con);
            break;
        case 0:
            Destroy(&con);
        default:
            return 0;
        }
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

谁在夜里看海.

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值