结构体实现静态通讯录

前言:

hello啊,两天未更是因为课实在太多。今晚腾出来时间写一篇如何使用结构体来实现静态通讯录的博客。让我们一边看,一边解析。Not much to say, show code.

C语言具体实现:

头文件:Contact.h

#define _CRT_SECURE_NO_WARNING 1
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#pragma warning(disable:6031)
#define MAX 100//表示通讯录存储联系人的最大上限
#define MAX_NAME 20
#define MAX_SEX 5
#define MAX_TELE 12
#define MAX_ADDR 30
//表示一个联系人的信息
typedef struct PeoInfo
{
    char name[MAX_NAME];
    char sex[MAX_SEX];
    int age;
    char tele[MAX_TELE];
    char addr[MAX_ADDR];
}PeoInfo;


typedef struct Contact
{
    PeoInfo data[MAX];//联系人信息构成的结构体数组
    int sz;//已记录的有效联系人个数
}Contact,*pContact;//将struct Contact类型重命名为Contact,将struct Contact*重命名为pContact



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

//增加联系人
void AddContact(Contact* pc);

//删除指定联系人
void DelContact(Contact* pc);

//查找指定联系人
void SearchContact(const Contact* pc);

//修改联系人信息
void ModifyContact(Contact* pc);

//显示联系人信息
void ShowContact(const Contact* pc);

//排序联系人信息
void SortContact(Contact* pc);

源文件:Contact.c

#define _CRT_SECURE_NO_WARNINGS 1
#include"contact.h"

//初始化通讯录
void InitContact(Contact* pc)
{
    pc->sz = 0;
    memset(pc->data, 0, sizeof(pc->data));//使用memset对结构体数组初始化为0
}

static int FindByName(const Contact* pc, char name[])
{
    int i = 0;
    for (int i = 0; i < pc->sz; i++)
    {
        if (0 == strcmp(pc->data[i].name, name))
        {
            return i;
        }
    }
    return -1;
}

//增加联系人
void AddContact(Contact* pc)
{
    if (pc->sz == MAX)
    {
        printf("通讯录已满,无法增加\n");
        return;//在函数里面直接return会终止函数,因为是void返回类型所以只写return就行。
    }
    printf("请输入联系人姓名:>");
    scanf("%s", pc->data[pc->sz].name);
    printf("请输入性别:>");
    scanf("%s", pc->data[pc->sz].sex);
    printf("请输入年龄:>");
    scanf("%d", &(pc->data[pc->sz].age));
    printf("请输入联系方式:>");
    scanf("%s", pc->data[pc->sz].tele);
    printf("请输入地址:>");
    scanf("%s", pc->data[pc->sz].addr);
    (pc->sz)++;//不加括号也没问题,因为->优先级大于++
    printf("添加成功\n");
}


//删除联系人
void DelContact(Contact* pc)
{
    char name[MAX_NAME] = { 0 };
    if (pc->sz == 0)
    {
        printf("通讯录为空,无法删除\n");
        return;
    }
    //删除
    //1.找到要删除的联系人->位置,下标
    printf("输入要删除人的名字:>");
    scanf("%s", name);
    int pos = FindByName(pc, name);
    if (pos == -1)
    {
        printf("要删除的人不存在\n");
        return;
    }
    int i = 0;
    //2.删除-删除pos位置上的数据,并让pos之后的数据前移
    for (i = pos; i < (pc->sz)-1; i++)
    {
        pc->data[i] = pc->data[i + 1];
    }
    (pc->sz)--;
    printf("删除成功\n");
}


//查找联系人信息
void SearchContact(const Contact* pc)
{
    char name[MAX_NAME] = { 0 };
    printf("请输入要查找的名字:>");
    scanf("%s", name);
    //查找
    int pos = FindByName(pc, name);
    //如果不存在
    if (pos == -1)
    {
        printf("查找的联系人不存在\n");
        return;
    }
    //如果存在
    //打印标题
    printf("%-10s %-5s %-4s %-12s %-30s\n",//加-号表示左对齐,加数字表示字符串长度
        "姓名", "性别", "年龄", "电话", "地址");
    //打印数据内容
    printf("%-10s %-5s %-4d %-12s %-30s\n",
        pc->data[pos].name, pc->data[pos].sex, pc->data[pos].age, pc->data[pos].tele,pc->data[pos].addr);
}


//修改联系人信息
void ModifyContact(Contact* pc)
{
    char name[MAX_NAME] = { 0 };
    printf("请输入要修改联系人的名字:>");
    scanf("%s", name);
    //查找
    int pos = FindByName(pc, name);
    //如果不存在
    if (pos == -1)
    {
        printf("要修改的联系人不存在\n");
        return;
    }
    //修改
    printf("请输入联系人姓名:>");
    scanf("%s", pc->data[pos].name);
    printf("请输入性别:>");
    scanf("%s", pc->data[pos].sex);
    printf("请输入年龄:>");
    scanf("%d", &(pc->data[pos].age));
    printf("请输入联系方式:>");
    scanf("%s", pc->data[pos].tele);
    printf("请输入地址:>");
    scanf("%s", pc->data[pos].addr);

    printf("修改成功\n");
}


//显示联系人信息
void ShowContact(const Contact* pc)
{
    int i = 0;
    //打印标题
    printf("%-10s %-5s %-4s %-12s %-30s\n",//加-号表示左对齐,加数字表示字符串长度
        "姓名", "性别", "年龄", "电话", "地址");
    for (i = 0; i < pc->sz; i++)
    {
        //打印数据内容
        printf("%-10s %-5s %-4d %-12s %-30s\n",
            pc->data[i].name, pc->data[i].sex, pc->data[i].age, pc->data[i].tele, pc->data[i].addr);
    }
}

static int cmp_by_name(const void* e1, const void* e2)
{
    return strcmp(((PeoInfo*)e1)->name, ((PeoInfo*)e2)->name);
}

void SortContact(Contact* pc)
{
    qsort(pc->data, pc->sz, sizeof(PeoInfo), cmp_by_name);
    printf("排序成功\n");
}

测试代码:

void menu()//菜单
{
    printf("*******************************\n");
    printf("********1.Add     2.Del********\n");
    printf("********3.Search  4.Modify*****\n");
    printf("********5.Show    6.sort*******\n");
    printf("************0.exit*************\n");
    printf("*******************************\n");
}
enum Options//使用枚举列举出所有选项
{
    EXIT,
    ADD,
    DEL,
    SEARCH,
    MODIFY,
    SHOW,
    SORT
};
int main()
{
    int input = 0;
    Contact con;//通讯录
    InitContact(&con);//初始化通讯录
    do
    {
        menu();
        printf("请选择:>");
        scanf("%d", &input);
        switch (input)
        {
        case ADD:
            AddContact(&con);
            break;
        case DEL:
            DelContact(&con);
            break;
        case SEARCH:
            SearchContact(&con);
            break;
        case MODIFY:
            ModifyContact(&con);
            break;
        case SHOW:
            ShowContact(&con);
            break;
        case SORT:
            SortContact(&con);
            break;
        case EXIT:
            printf("退出通讯录\n");
            break;
        default:
            printf("选择错误,请重试\n");
            break;
        }

    } while (input);
    return 0;
}

测试结果展示:

(王五的添加省略了,因为过程都一样,不过多展示)

这是简单的展示,仅仅展示了添加联系人和展示通讯录列表两个功能,感兴趣的小伙伴可以保存代码自己运行尝试其他的功能。

重点解析:

1.为什么要分.h,.c文件?

因为这个通讯录这个程序是一个简单的工程,在实际工作中,一个工程的不同板块是由不同的人来实现的。就比如此程序中写contact.c文件的就是来负责函数实现的。所以分别写成.h文件和.c文件,contact.c文件主要用来实现各种函数,contact.h文件主要用来声明这些函数并且定义一些通讯录中的最值成宏(方便修改,并且可读性强,可维护性高)以及创建结构体。

并且这样其他.c文件在使用时只需引用头文件#include"contact.h"即可调用通讯录。

2.为何在测试中要枚举出所有选项?

因为我们是按照菜单中的序号来进行枚举,保证枚举常量的值就等于其序号(第一个枚举常量默认值为0,后面的会依次加1)。这样在switch分支中就可用枚举常量代替数字1,2,3.....。这样代码的可读性就变强了,并且可维护性也变高了。

3.在contact.c文件中为什么有的函数,比如FindByName,需要加static呢?

因为我们知道在程序写好了之后,有些函数,代码属于机密或者隐私,不想让使用者调用或者查看,我们就可以使用static修饰函数使之失去外部连接属性,这样使用者就无法再通过头文件调用了。

4.代码中有些部分看不懂怎么办?

私信我,或者在评论区提出。我会迅速解答。放心提问,问到就是学到!

扫描二维码关注公众号,回复: 17157578 查看本文章

Disadvantage:

此通讯录的信息是短暂的,打开程序存储后。退出再进来信息就没了。因为信息并未真正存储在计算机(文件)中。所以我们称这个是静态通讯录。

后续我会抓紧更新动态通讯录,可以保证信息存储在电脑中,就跟手机上通讯录的一样,可以随时查看使用。

结语:

ok辣,本章到这里就结束了。每天学一点就是进步一点!蛰久者,飞必高!

祝愿我们大家都能保持空杯心态继续努力,厚积薄发!!!

最后还是老话:路漫漫其修远兮,吾将上下而求索!!!

猜你喜欢

转载自blog.csdn.net/qq_74292674/article/details/129698730