自定义类型的运用:通讯录的实现

本文所有代码的链接🔗

整体思路

生活中使用的通讯录一般的功能有:联系人的姓名,电话号码,家庭住址,这里我们就要实现这几个功能,我们还可以添加一些如联系人年龄,清空通讯录,按姓氏排列联系人的功能。


由于实现通讯录功能需要较多的函数,以及较多的变量,所以我们可以分别建立源项目。

contact.h定义了所有宏常量,定义了主要的结构体,声明主要函数。使得之后再看代码时有一个较为清晰的概念。

contact.c是根据contact.h的声明具体写出了实现通讯录功能所需要的函数

test.c是用来测试通讯录功能的,只要搭建一个合理的框架来合理地使用contact.c中的函数,就可以实现通讯录的功能。

接下来看看每个函数的具体实现

通讯录作主体的定义

通讯录有许多联系人,而每个联系人又有姓名,年龄,电话号码等各种信息,所以用struct定义一个联系人person类,每个联系人的具体信息就是这个类的成员变量。

而通讯录中又有许多的联系人,这最好用一个数组来储存,同时再使用一个变量来记录通讯录中联系人的数量以方便后续操作。所以用struct定义一个通讯录Contact类型,存放所有联系人的数组以及联系人数量就是这个结构体的成员变量。

contact.h

#define MAX_name 20
#define MAX_tele 20
#define MAX_addr 30
#define MAX 100

typedef struct person//每个联系人的信息
{
    char name[MAX_name];//联系人姓名
    int age;//联系人年龄
    int tele[MAX_tele];//联系人号码
    char addr[MAX_addr];//联系人住址
}person;//将struct person类型重命名为person方便写入

typedef struct Contact//定义了通讯录中所包含的信息
{
    person data[MAX];//结构体数组用来存放每个联系人的信息
    int sz;//联系人数量
}Contact,*pcContact;//将struct Contact类型重命名为Contact,指针命名为pcContact

在用户操作前,首先先将通讯录初始化,所有数据都设为0

注意在函数内部操作结构体的所有动作,都必须通过指针

void InitContact(Contact* pc)//和结构体有关的函数传参时一定要传结构体指针,这样速度快效率高
{
    pc->sz = 0;
    memset(pc->data, 0, sizeof(pc->data));
}

添加联系人

void addmember(Contact* pc)//添加新成员
{
    if (pc->sz == MAX)
    {
        printf("通讯录成员已满,无法再添加新成员\n");
    }
    printf("请输入名字\n");
    scanf("%s", pc->data[pc->sz].name);
    printf("请输入年龄\n");
    scanf("%d", &(pc->data[pc->sz].age));
    printf("请输入电话号码\n");
    scanf("%s", pc->data[pc->sz].tele);
    printf("请输入地址\n");
    scanf("%s", pc->data[pc->sz].addr);

    pc->sz++;
    printf("添加成功\n");
    DisplayContact(pc);
}

在对通讯录操作后,应该让用户再看一下通讯录,以确保他们的修改,这里写一个打印通讯录所有联系人的函数

void DisplayContact(Contact* pc)//进行操作后向用户展示更新后的通讯录
{
    char name[] = "姓名";
    char age[] = "年龄";
    char tele[] = "电话";
    char addr[] = "地址";
    printf("%20s%20s%20s%20s\n", name, age, tele, addr);
    for (int i = 0; i < pc->sz; i++)
    {
        printf("%20s", pc->data[i].name);
        printf("%20d", pc->data[i].age);
        printf("%20s", pc->data[i].tele);
        printf("%20s", pc->data[i].addr);
        printf("\n");
    }
    printf("\n");
}

删除联系人

void delmember(Contact* pc)
{
    if (pc->sz == 0)
    {
        printf("当前通讯录无成员,无法删除\n");
        return;
    }
    printf("请输入想删除的成员名字\n");//通过名字来查找要删除的联系人
    int pos=Find_by_name(pc);//将查找结果返回给pos,找到返回联系人数组下标,找不到返回-1
    if (pos != -1)//如果找到
    {
        for (pos; pos < pc->sz; pos++)
        {
            pc->data[pos] = pc->data[pos + 1];//由于是数组,不能删除,只能覆盖,将要删除的位置后面的数据向前覆盖一位
        }
        pc->sz--;//联系人数量-1
        DisplayContact(pc);
        return;
    }
    else
    {
        printf("要删除的成员不存在\n");
        DisplayContact(pc);
    }
}

按名字寻找联系人的函数

上面函数中int pos=Find_by_name(pc); 是将按名字寻找结果返回给pos变量,由于按名字寻找的功能对于通讯录来说十分重要,所以这里直接抽离出一个函数来实现,而不用每次都在需要用的时候临时写

int Find_by_name(Contact* pc)//通过输入成员名字来查找成员,找到返回成员在data数组中的下标,找不到返回-1
{
    char name[MAX_name] = { 0 };
    scanf("%s", name);//输入一个姓名
    int pos = 0;
    for (int i = 0; i < pc->sz; i++)//将这个姓名在联系人中遍历寻找
    {
        if (strcmp(name, pc->data[i].name) == 0)//找到返回下标
        {
            pos = i;
            return pos;
            break;
        }
    }
    return -1;//找不返回-1
}

寻找联系人

void searchmember(Contact* pc)
{
    printf("请输入你想寻找的成员的名字\n");
    int pos=Find_by_name(pc);
    if (pos != -1)
    {
        char name[] = "姓名";
        char age[] = "年龄";
        char tele[] = "电话";
        char addr[] = "地址";
        printf("%20s%20s%20s%20s\n", name, age, tele, addr);
        printf("%20s", pc->data[pos].name);
        printf("%20d", pc->data[pos].age);
        printf("%20s", pc->data[pos].tele);
        printf("%20s", pc->data[pos].addr);
        printf("\n");
        printf("\n");
    }
    else
    {
        printf("未找到该成员\n");
        printf("\n");
    }
}

修改联系人

void modifymember(Contact* pc)
{
    if (pc->sz == 0)
    {
        printf("当前通讯录无成员,无法修改\n");
        return;
    }
    printf("请输入你想修改的成员的名字\n");
    int pos=Find_by_name(pc);
    if (pos != -1)
    {
        printf("请重新输入名字\n");
        scanf("%s", pc->data[pos].name);
        printf("请重新输入年龄\n");
        scanf("%d", &(pc->data[pos].age));
        printf("请重新输入电话号码\n");
        scanf("%s", pc->data[pos].tele);
        printf("请重新输入地址\n");
        scanf("%s", pc->data[pos].addr);
        DisplayContact(pc);
        return;
    }
    printf("未找到要修改的成员\n");
    printf("\n");
}

清空通讯录

void resetContact(Contact* pc)
{
    printf("确认要清空所有联系人吗?\n");
    printf("请输入:1.我再想想  2.确认\n");
    int confirm = 0;
    scanf("%d", &confirm);
    if (2 == confirm)
    {
        memset(pc, 0, sizeof(pc->data));//相当于又初始化了一次
    }
    else
        return;
}

按姓氏给联系人排序

使用快速排序qsort函数,还需要自己写一个比较函数(cmp_by_name)

快速排序的相关知识

int cmp_by_name(const void* p1, const void* p2)
{
    return strcmp(((person*)p1)->name, ((person*)p2)->name);
}


void sortmember_name(Contact* pc)
{
    if (pc->sz < 2)
    {
        printf("当前通讯录成员无法排序\n");
        printf("\n");
        return;
    }
    qsort(pc->data, pc->sz, sizeof(pc->data[0]), cmp_by_name);
    DisplayContact(pc);
    printf("\n");
}

最后看一下test.c

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<string.h>
#include"contact.h"


enum option
{
    exit,//0
    add,//1
    del,//2
    search,//3
    modify,//4
    show,//5
    reset,//6
    sort//7
};
int main()
{
    int input = 0;
    Contact con;
    InitContact(&con);
    do
    {
        menu();
        printf("您想执行的操作\n");
        scanf("%d", &input);
        switch (input)
        {
        case add://用枚举定义常量可以让程序的可读性增加
            addmember(&con);
            break;
        case del:
            delmember(&con);
            break;
        case search:
            searchmember(&con);
            break;
        case modify:
            modifymember(&con);
            break;
        case show:
            DisplayContact(&con);
            break;
        case reset:
            resetContact(&con);
            break;
        case sort:
            sortmember_name(&con);
            break;
        case exit:
            break;
        default:
            printf("请输入正确的操作数\n");
            break;
        }
    } while (input);
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值