c语言通讯录实现,静态和动态扩容版本


我们可以先想一下通讯录的信息包含有哪些
姓名 年龄 性别 地址 手机号…等(我们可以额外增加其他的内容)
通讯录的一些功能实现如:增加联系人、修改联系人、查看联系人、整理联系人(由首字母开始向后)、查找联系人和删除联系人
首先我们需要创建三个文件进行整理
test.c用来测试代码正常运行
contact.h作为头文件来进行函数分装的声明
contact.c来进行函数的实现功能

1.创建菜单栏

首先创建一个菜单,菜单包含着我们通讯录的一些功能选择界面
代码如下

void menu()
{
    printf("********************************************\n");
    printf("********  1.add      2.delete      *********\n");
    printf("********  3.search   4.modify      *********\n");
    printf("********  5.show     6.sort        *********\n");
    printf("********  0.exit                   *********\n");
    printf("********************************************\n");
}

2.主函数入口

当我们设定好了菜单,在主函数中设置一个输入选项,选中该选项来进行实现功能,设定一个dowhile循环来保证代码至少执行一次
当输入0时0为假,循环不会继续退出循环,当输入超出范围内的数字,重新输入

int main()
{
    int import;
    do
    {
       menu();
    printf("请输入你的选项:>>>>>>>>");
    scanf("%d", &import);
    switch (import)
    {
    case 1:
        break;
    case 2:
        break;
    case 3:
        break;
    case 4:
        break;
    case 5:
        break;
    case 6:
        break;
    case 0:
        printf("退出通讯录\n");
        break;
    default:
        printf("输入错误\n");
        break;
    }
    } while (import);

3.自定义数据类型的实现(创建通讯录)

因为我们通讯录中需要包含的信息有很多,我们可以使用struct来自定义类型,后续可以通过结构体成员来访问
结构体类型我们只是声明,我们可以将声明放到头文件中
这里我们可以将数组的元素define定义到头文件中,这样我们可以直接进行修改,不需要从结构体内部修改

#define Max 100
#define Name_Max 20
#define Sex_Max 5
#define Address_Max 30
#define Tele_Max 12
typedef struct information//成员的信息
//typedef 修改成员名信息为PeoInfor
{
    char name[Name_Max];
    int age;
    char sex[Sex_Max];
    char address[Address_Max];
    char tele[Tele_Max];
}PeoInfor;

当我们设置好了成员名的信息后,因为我们想要的联系人不止一个,我们需要定义一个数组,数组可以大一些,比如100,放100个联系人
可以将这个数组写为PeoInfor Data[100],这样我们就有了100个元素来存放成员信息。
但是我们不知道我们一共添加了几个联系人,通讯录目前共多少个,设置一个int sz来存放我们联系人的个数,因为数组下标是从0开始的
这样我们就可以写一个结构体将两个数组存放起来

typedef struct Contact
{
     //创建通讯录
    PeoInfor Data[100];//存放100个信息
    int sz;//当前通讯录的信息个数
}Contact;

在main函数中创建刚才创建的结构体类型

 Contact con;//分装自定义类型

4.初始化通讯录信息

我们将Contact con中的结构体成员和成员个数初始化为0
main.c

   InitContact(&con);

这里我们声明一下
Contact.h

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

Contact.c

void InitContact(Contact *pc)
{
    assert(pc);//断言
    pc->sz = 0;//结构体的个数植为0
    memset(pc->Data, 0, sizeof(pc->Data));//初始化pc->sz整个数组的大小
    //memset函数可以将制定的数组中所有字节数置为指定数值
    第一个值为元素首地址,第二个为值为0,第三个为元素所占用的字节数
}

5.当我们的初始化完成后,接下来就是选择语句中的函数功能实现了

1.Add函数实现(添加通讯录)

void AddContact(Contact *pc)
{
    assert(pc);
    if (pc->sz == Max)
    //这里我们的条件是如果通讯录已经100,无法添加
    {
        printf("您好,通讯录已满,无法添加\n");
        return;
    }
    //增加一个人的信息
    printf("请输入名字:>");
    scanf("%s", pc->Data[pc->sz].name);//输入下标为0的结构体类型
    printf("请输入年龄:>");
    scanf("%d", &(pc->Data[pc->sz].age));
    printf("请输入性别:>");
    scanf("%s", pc->Data[pc->sz].sex);
    printf("请输入地址:>");
    scanf("%s", pc->Data[pc->sz].address);
    printf("请输入电话:>");
    scanf("%s", pc->Data[pc->sz].tele);
    pc->sz++;//sz++,联系人加1
}

2.显示联系人

void ShowContact( Contact *pc)
{
    assert(pc);
    printf(" %-20s\t%-4s\t%-4s\t%-20s\t%-12s\n", "名字", "年龄", "性别", "地址", "电话");
    //访问的是结构体中的成员信息,循环方式打印
    for (int i = 0; i < pc->sz; i++)
    {
        printf(" %-20s\t%-4d\t%-4s\t%-20s\t%-12s\n", pc->Data[i].name,
               pc->Data[i].age,
               pc->Data[i].sex,
               pc->Data[i].address,
               pc->Data[i].tele);
    }
}

3.删除联系人

  int Find_By_Name(const Contact* pc,char name[])//查找函数分装
    {
        int i = 0;
        for (i = 0; i < pc->sz; i++)
        {
            if (strcmp(pc->Data[i].name, name) == 0) // 数组中与想要的名字相同进入
            {
                return i;
                break;
            }
    }
    return -1;
   }
    
void DelContact(Contact* pc)
{
    assert(pc);
    char name[Name_Max] = {0};
    //这里后面我们需要创建一个输入指定名字的变量
    int i = 0;
    if (pc->sz == 0)//条件如果为0,没有联系人
    {
        printf("通讯录为空,无法删除\n");
    }
    //找到要删除的人
    printf("请输入你要删除的人的名字:>>>>");
    scanf("%s", name);
    //查找
    int ret = Find_By_Name(pc, name);//查找我们输入的名字是否在数组中,并返回
    //因为我们后面还需要使用到Find函数,所以我们需要分装出来
    if(ret==-1)
    {
        printf("要删除的人不存在此备忘录\n");
        return;
    }
    // 删除
    for (i = ret; i < pc->sz-1;i++)//sz-1为98,程序+1不能越界访问
    {
        pc->Data[i] = pc->Data[i + 1];
    }
    pc->sz--;//将删除的下标益处
    printf("删除成功\n");
}

4.查找联系人

void SearchContact( const Contact* pc)
{
    assert(pc);
    char name[Name_Max] = {0};
    printf("请输入要查找人的名字:>>>");
    scanf("%s", name);
   int pos =  Find_By_Name(pc, name);
   if(pos==-1)
   {
       printf("该通讯录没有要查找的联系人\n");
       return;
   }
    printf(" %-20s\t%-4s\t%-4s\t%-20s\t%-12s\n", "名字", "年龄", "性别", "地址", "电话");
        printf(" %-20s\t%-4d\t%-4s\t%-20s\t%-12s\n", pc->Data[pos].name,
               pc->Data[pos].age,
               pc->Data[pos].sex,
               pc->Data[pos].address,
               pc->Data[pos].tele);
}

5.修改联系人

void ModifyContact(Contact* pc)
{
    assert(pc);
    char name[Name_Max] = {0};
    printf("请输入修改人的名字:>>>>");
    scanf("%s", name);
    int pos = Find_By_Name(pc, name);
    if(pos==-1)
    {
        printf("你想要修改的名字未在通讯录中\n");
        return;
    }
    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].address);
    printf("请输入电话:>");
    scanf("%s", pc->Data[pos].tele);
    printf("修改完成\n");//提示
}

6.联系人排序整理

int cmp_name(const void* e1, const void* e2)
{
	return (strcmp(((Contact*)e1)->Data->name, ((Contact*)e2)->Data->name));
    //比较两个数
}
//联系人排序
void SortContact(Contact* pc)
{
	assert(pc);
	//这里我们需要引入qsort函数,来比较内存中的字节的大小,进行排序
	qsort(pc->Data, pc->sz, sizeof(pc->Data[0]), cmp_name);
	//第一个参数是首元素地址,第二个为元素的个数,第三个为类型字节数,第四个参数为比较
	//打印
	printf("排序完成\n");
	ShowContact(pc);//打印一下
}

test.c 测试

#include"contact.c"
void menu()
{
    printf("********************************************\n");
    printf("********  1.add      2.delete      *********\n");
    printf("********  3.search   4.modify      *********\n");
    printf("********  5.show     6.sort        *********\n");
    printf("********  0.exit                   *********\n");
    printf("********************************************\n");
}
int main()
{
    int import;
    Contact con;//分装自定义类型
    //初始化通讯录
    InitContact(&con);
    do
    {
       menu();
    printf("请输入你的选项:>>>>>>>>");
    scanf("%d", &import);
    switch (import)
    {
    case 1:
        AddContact(&con);
        break;
    case 2:
        DelContact(&con);
        break;
    case 3:
        SearchContact(&con);
        break;
    case 4:
        ModifyContact(&con);
        break;
    case 5:
        ShowContact(&con);
        break;
    case 6:
        SortContact(&con);
        break;
    case 0:
        printf("退出通讯录\n");
        break;
    default:
        printf("输入错误\n");
        break;
    }
    } while (import);
    
    return 0;
}

Contact.h函数声明

#include<stdio.h>
#include<string.h>
#include<assert.h>
#include<stdlib.h>
#define Max 100
#define Name_Max 20
#define Sex_Max 5
#define Address_Max 30
#define Tele_Max 12
//声明
typedef struct information
{
    char name[Name_Max];
    int age;
    char sex[Sex_Max];
    char address[Address_Max];
    char tele[Tele_Max];
}PeoInfor;
typedef struct Contact
{
     //创建通讯录
    PeoInfor Data[100];//存放100个信息
    int sz;//当前通讯录的信息个数
}Contact;
void InitContact(Contact* pc);//初始话通讯录
void AddContact(Contact* pc); //增加联系人信息   
void ShowContact( Contact* pc);//打印联系人
void DelContact(Contact* pc);//删除指定联系人
void SearchContact(const Contact* pc);//查找指定联系人
void ModifyContact(Contact* pc);//修改联系人
void SortContact(Contact* pc);//整理联系人

Contact.c函数实现

#include"contact.h"
//实现
void InitContact(Contact *pc)
{
    assert(pc);
    pc->sz = 0;
    memset(pc->Data, 0, sizeof(pc->Data));//初始化pc->sz整个数组的大小
}
void AddContact(Contact *pc)
{
    assert(pc);
    if (pc->sz == Max)
    {
        printf("您好,通讯录已满,无法添加\n");
        return;
    }
    //增加一个人的信息
    printf("请输入名字:>");
    scanf("%s", pc->Data[pc->sz].name);//输入下标为0的结构体类型
    printf("请输入年龄:>");
    scanf("%d", &(pc->Data[pc->sz].age));
    printf("请输入性别:>");
    scanf("%s", pc->Data[pc->sz].sex);
    printf("请输入地址:>");
    scanf("%s", pc->Data[pc->sz].address);
    printf("请输入电话:>");
    scanf("%s", pc->Data[pc->sz].tele);
    pc->sz++;//sz++,联系人加1
}
void ShowContact( Contact *pc)
{
    assert(pc);
    printf(" %-20s\t%-4s\t%-4s\t%-20s\t%-12s\n", "名字", "年龄", "性别", "地址", "电话");
    for (int i = 0; i < pc->sz; i++)
    {
        printf(" %-20s\t%-4d\t%-4s\t%-20s\t%-12s\n", pc->Data[i].name,
               pc->Data[i].age,
               pc->Data[i].sex,
               pc->Data[i].address,
               pc->Data[i].tele);
    }
}
    int Find_By_Name(const Contact* pc,char name[])//查找函数分装
    {
        int i = 0;
        for (i = 0; i < pc->sz; i++)
        {
            if (strcmp(pc->Data[i].name, name) == 0) // 数组中与想要的名字相同进入
            {
                return i;
                break;
            }
    }
    return -1;
    }
void DelContact(Contact* pc)
{
    assert(pc);
    char name[Name_Max] = {0};
    int i = 0;
    if (pc->sz == 0)
    {
        printf("通讯录为空,无法删除\n");
    }
    //找到要删除的人
    printf("请输入你要删除的人的名字:>>>>");
    scanf("%s", name);
    //查找
    int ret = Find_By_Name(pc, name);
    if(ret==-1)
    {
        printf("要删除的人不存在此备忘录\n");
        return;
    }
    // 删除
    for (i = ret; i < pc->sz-1;i++)//sz-1为98,程序+1不能越界访问
    {
        pc->Data[i] = pc->Data[i + 1];
    }
    pc->sz--;//将删除的下标益处
    printf("删除成功\n");
}
void SearchContact( const Contact* pc)
{
    assert(pc);
    char name[Name_Max] = {0};
    printf("请输入要查找人的名字:>>>");
    scanf("%s", name);
   int pos =  Find_By_Name(pc, name);
   if(pos==-1)
   {
       printf("该通讯录没有要查找的联系人\n");
       return;
   }
    printf(" %-20s\t%-4s\t%-4s\t%-20s\t%-12s\n", "名字", "年龄", "性别", "地址", "电话");
        printf(" %-20s\t%-4d\t%-4s\t%-20s\t%-12s\n", pc->Data[pos].name,
               pc->Data[pos].age,
               pc->Data[pos].sex,
               pc->Data[pos].address,
               pc->Data[pos].tele);
}
void ModifyContact(Contact* pc)
{
    assert(pc);
    char name[Name_Max] = {0};
    printf("请输入修改人的名字:>>>>");
    scanf("%s", name);
    int pos = Find_By_Name(pc, name);
    if(pos==-1)
    {
        printf("你想要修改的名字未在通讯录中\n");
        return;
    }
    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].address);
    printf("请输入电话:>");
    scanf("%s", pc->Data[pos].tele);
    printf("修改完成\n");
}
int cmp_name(const void* e1, const void* e2)
{
	return (strcmp(((Contact*)e1)->Data->name, ((Contact*)e2)->Data->name));
    //比较两个数
}
//联系人排序
void SortContact(Contact* pc)
{
	assert(pc);
	qsort(pc->Data, pc->sz, sizeof(pc->Data[0]), cmp_name);
	//打印
	printf("排序完成\n");
	ShowContact(pc);//打印一下
}

动态开辟空间

因为我们的通讯录需要设定创建的人数是有限的,太高会浪费内存,过少用户会添加不了新的信息到通讯录,所以我们可以使用动态来开辟一个空间

typedef struct Contact
{
     //创建通讯录
    PeoInfor* Data;//指向了存放的人的信息
    int sz;//当前通讯录的信息个数
    int capacity; //来记录我们当前最大的容量
}Contact;

当我们将结构体类型设置好后,我们需要将我们结构体内所有的信息进行初始化
所以在主函数中定义一个函数进行初始化
1.通讯录的个数首先肯定是从0开始
2.而我们的Data的个数先设置多少个呢,这里我们可以在.h文件中define声明一下,Default_Sz来初始化为3个,这样也方便我们的测试
我们直接使用calloc来开辟一个动态空间,将元素的个数,和需要开辟空间的大小放入,引入一个临时的指针来接收一下开辟的动态空间,判断一下是否开辟成功,然后我们可以将ptr这个指针指向的空间赋给原空间pc->Data。
3.capacity来作为我们的一个容量,来记录我们容量的变化,因为我们的容量默认为Default_Sz个,后续用来判断,如果容量满了,我们就可以进行扩容

void InitContact(Contact *pc)
{
    assert(pc);
    pc->sz = 0;
    PeoInfor* ptr =(PeoInfor*)calloc(Default_Sz,sizeof(PeoInfor));
     //第一个:Default_Sz个元素,第二个:PeoInfor的字节空间大小,
    if(ptr==NULL)
    {
        perror("InitContact");
        return;
    }
    pc->Data = ptr;
    pc->capacity = Default_Sz;
}

增加联系人(扩容)

void Expand_Capacity(Contact* p)//判断容量是否满了
{
    if (p->sz == p->capacity)//这里是判断我们默认的容量
    {
       //增容
    PeoInfor* ptr = (PeoInfor*)realloc(p->Data, (p->capacity+Inc_Sz)* sizeof(PeoInfor));
    //这里的realloc可以调整我们当前已经动态开辟空间的大小
    //第一个放入我们的起始位置, 第二个是我们的容量(3+2)*类型的大小(算上我们当初已经拥有的容量)
    if(ptr==NULL)
    {
        perror("Expand_Capacity::");
        return;
    }
       p->Data = ptr;
       p->capacity += Inc_Sz;
    }
}
//动态
void AddContact(Contact *pc)
{
    assert(pc);
    Expand_Capacity(pc);//这里我们直接可以做一个扩容的函数
    // 增加一个人的信息
    printf("请输入名字:>");
    scanf("%s", pc->Data[pc->sz].name);//输入下标为0的结构体类型
    printf("请输入年龄:>");
    scanf("%d", &(pc->Data[pc->sz].age));
    printf("请输入性别:>");
    scanf("%s", pc->Data[pc->sz].sex);
    printf("请输入地址:>");
    scanf("%s", pc->Data[pc->sz].address);
    printf("请输入电话:>");
    scanf("%s", pc->Data[pc->sz].tele);
    pc->sz++;//sz++,联系人加1
}

销毁动态开辟的空间
当我们系统已经结束后,选择为0,退出时,我们需要销毁我们动态开辟的空间

Destory_Contact(&con);//这里我们在主函数中实现,用来销毁我们动态开辟的空间

声明

void Destory_Contact(Contact* pc);//销毁通讯录

实现

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

扩容成功界面

代码实现扩容成功
在这里插入图片描述

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值