文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

C语言代码实现通讯录管理系统

2024-04-02 19:55

关注

本文实例为大家分享了C语言实现通讯录管理系统,供大家参考,具体内容如下

一、需求分析

运用C语言实现一个简单的通讯录管理系统,要求对数据有 增删改查清排显 等功能的实现(这里由于还没学到文件,所以下面所有的存储都是在内存中,也就是当程序结束的时候添加的信息都会清空掉 - 后续会加以改进的)

二、程序结构

在基本的程序设计中,都会将项目分为三个文件:

1、test.c - 主函数(负责调用各个功能的接口)
2、contact.c - 实现各个模块的功能
3、contact.h - 用于存放头文件、宏定义、函数声明等

三、头文件内容的介绍

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

#define MAX 1000
#define NAME_MAX 20
#define SEX_MAX 5
#define ADDR_MAX 50
#define TELE_MAX 12

#define DEFAULT_SZ 3

// 数组版本
//typedef struct PeoInfo
//{
//    char name[NAME_MAX];
//    int age;
//    char sex[SEX_MAX];
//    char addr[ADDR_MAX];
//    char tele[TELE_MAX];
//}PeoInfo;
//
//typedef struct Contact
//{
//    //PeoInfo data[MAX];  // 存放信息
//    PeoInfo data[MAX];
//    int sz; // 存放通讯录有几个人的信息
//}Contact;

// 每个人的基本信息
typedef struct PeoInfo
{
    char name[NAME_MAX];
    int age;
    char sex[SEX_MAX];
    char addr[ADDR_MAX];
    char tele[TELE_MAX];
}PeoInfo;

typedef struct Contact
{
    //PeoInfo data[MAX];  // 存放信息
    PeoInfo* data;
    int sz; // 存放通讯录有几个人的信息
    int capacity; // 记录当前通讯录的最大容量
}Contact;


void DestoryContact(Contact* pc);
void InitContact(Contact* pc);
void AddContact(Contact* pc);
void ShowContact(const Contact* pc);
void DeleteContact(Contact* pc);
void SearchContact(const Contact* pc);
void ModifyContact(Contact* pc);
void SortContact(Contact* pc);

里面被注释的代码则是之前的数组版本,规定死了通讯录大小;而下面我们会用动态增容来进行实现。头文件里面用宏定义主要为了之后我们更改对应的大小的时候更加的方便;结构体主要存放的就是三大部分:

1. 一个指向每个人基本信息的结构体指针;2. sz记录着通讯录的记录条数;3. capacity 存放通讯录的容量

四、模块化实现各个功能

(1)主函数实现

int main()
{
    int input = 0;
    Contact con; // 创建通讯录

    InitContact(&con);

    do
    {
        menu();
        printf("请选择:->");
        scanf("%d", &input);

        switch (input)
        {
        case ADD:
            AddContact(&con);
            break;
        case DEL:
            DeleteContact(&con);
            break;
        case SEARCH:
            SearchContact(&con);
            break;
        case MODIFY:
            ModifyContact(&con);
            break;
        case SORT:
            SortContact(&con);
            break;
        case SHOW:
            ShowContact(&con);
            break;
        case EXIT:
            DestoryContact(&con);
            printf("退出\n");
            break;
        default:
            printf("输入错误,请重新输入\n");
            break;
        }
    } while (input);

    return 0;
}

一般函数的主函数里面都可以用do ……while结构来控制程序的执行顺序,在case后面用的则是 枚举常量 ,这样能做到更好的见名知意。

(2)初始化通讯录

void InitContact(Contact* pc)
{
    assert(pc);
    pc->sz = 0;
    PeoInfo* tmp = (PeoInfo*)malloc(DEFAULT_SZ * sizeof(PeoInfo));
    if (tmp != NULL)
    {
        pc->data = tmp;
    }
    else
    {
        printf("InitContact()::%s\n", strerror(errno));
    }

    pc->capacity = DEFAULT_SZ;
}

这里设定了通讯录的起始大小,后面可以通过动态增容来扩大(而数组版本的话就没有这么灵活了)

(3)添加联系人信息

void check_capacity(Contact* pc)
{
    assert(pc);
    if (pc->sz == pc->capacity)
    {
        // 增容
        PeoInfo* tmp = (PeoInfo*)realloc(pc->data, (pc->capacity + 2)*sizeof(PeoInfo));
        if (tmp != NULL)
        {
            pc->data = tmp;
            pc->capacity += 2;
            printf("增容成功\n");
        }
        else
        {
            printf("InitContact()::%s\n", strerror(errno));
        }
    }
}

void AddContact(Contact* pc)
{
    assert(pc);
    check_capacity(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].addr);
    printf("电话:");
    scanf("%s", pc->data[pc->sz].tele);
    
    pc->sz++;
    printf("添加成功\n");
}

这里实现了一个check_capacity 的接口,用来判断当前通讯录是否存满了;若满了则进行扩容(一般按2倍进行扩容),注意:添加成功后需要对 sz++

(4)删除联系人信息

int FindByName(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;
        }
    }
    return -1;
}

void DeleteContact(Contact* pc)
{
    char name[NAME_MAX] = { 0 };
    assert(pc);

    if (pc->sz == 0)
    {
        printf("通讯录为空\n");
        return;
    }

    // 根据输入的人名进行删除
    printf("请输入要删除的人名:");
    scanf("%s", name);

    int pos = FindByName(pc, name);

    if (pos == -1)
    {
        printf("要删除的人不存在\n");
    }
    else
    {
        // 删除
        //int j = 0;
        //for (j = pos; j < pc->sz-1; j++)  // sz-1为了防止j+1非法访问
        //{
        //    pc->data[j] = pc->data[j + 1];
        //}

        //pc->sz--;
        //printf("删除成功\n");
        //if (pc->sz>1)
        memmove((pc->data) + pos, (pc->data) + pos + 1, (pc->sz - pos)*sizeof(PeoInfo));
        pc->sz--;
    }
}

这里我就只做了按照名字进行删除,你们也可以都尝试一下哟。下面写了两种删除方法(这里的按名字删除前需要进行查找,因此我们也可以直接使用我们下面要实现的查找函数,但如果查找里面进行了其他功能,那时不能直接使用的哟)

(5)查找联系人信息

void SearchContact(const Contact* pc)

{
    char name[NAME_MAX] = { 0 };
    assert(pc);

    if (pc->sz == 0)
    {
        printf("通讯录为空\n");
        return;
    }

    printf("请输入要查找的姓名:");
    scanf("%s", name);
    int i = FindByName(pc, name);

    if(-1 == i)
    {
        // 没有找到
        printf("你要查找的人不存在\n");
    }
    else
    {
        // 找到了
        printf("%-10s\t%-5s\t%-5s\t%-20s\t%-13s\n", 
                "姓名", "年龄", "性别", "地址", "电话");
        printf("%-10s\t%-5d\t%-5s\t%-20s\t%-13s\n",
            pc->data[i].name, pc->data[i].age, pc->data[i].sex, pc->data[i].addr, pc->data[i].tele);
    }
}

这里如果查找到了后,我打印显示了一下

(6)更改联系人信息

void ModifyContact(Contact* pc)
{
    char name[NAME_MAX] = { 0 };
    assert(pc);

    if (pc->sz == 0)
    {
        printf("通讯录为空\n");
        return;
    }

    printf("请输入要修改信息的姓名:");
    scanf("%s", name);

    int i = FindByName(pc, name);

    // 修改内容
    printf("新的名字:");
    scanf("%s", pc->data[i].name);
    printf("新的年龄:");
    scanf("%d", &(pc->data[i].age));
    printf("新的性别:");
    scanf("%s", pc->data[i].sex);
    printf("新的地址:");
    scanf("%s", pc->data[i].addr);
    printf("新的电话:");
    scanf("%s", pc->data[i].tele);

    printf("修改后的信息为:\n");

    printf("%-10s\t%-5s\t%-5s\t%-20s\t%-13s\n", "姓名", "年龄", "性别", "地址", "电话");
    printf("%-10s\t%-5d\t%-5s\t%-20s\t%-13s\n",
        pc->data[i].name, pc->data[i].age, pc->data[i].sex, pc->data[i].addr, pc->data[i].tele);
}

(7)显示所有联系人信息

void ShowContact(const Contact* pc)
{
    assert(pc);
    // 打印
    printf("%-10s\t%-5s\t%-5s\t%-20s\t%-13s\n", "姓名", "年龄", "性别", "地址", "电话");
    int i = 0;
    for (i = 0; i < pc->sz; i++)
    {
        printf("%-10s\t%-5d\t%-5s\t%-20s\t%-13s\n",
            pc->data[i].name, pc->data[i].age, pc->data[i].sex, pc->data[i].addr, pc->data[i].tele);
    }
}

直接遍历打印即可

(8)对联系人信息进行排序

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

int cmp_by_age(const void* e1, const void* e2)
{
    return ((PeoInfo*)e1)->age - ((PeoInfo*)e2)->age;
    // return strcmp(, ((PeoInfo*)e2)->name);
}

void SortContact(Contact* pc)
{
    int choice = 0;
    printf("请选择:(1、按姓名;2、按年龄)");
    scanf("%d", &choice);

    if (1 == choice)
    {
        qsort(pc->data, pc->sz, sizeof(pc->data[0]), cmp_by_name);

        printf("排序后的数据:\n");
        ShowContact(pc);
    }
    else if (2 == choice)
    {
        qsort(pc->data, pc->sz, sizeof(pc->data[0]), cmp_by_age);
        printf("排序后的数据:\n");
        ShowContact(pc);
    }
    else
    {
        printf("输入有误\n");
    }
}

这里使用qsort实现的排序,可以对 姓名 或 年龄进行排序的

(9)退出时销毁通讯录

void DestoryContact(Contact* pc)
{
    assert(pc);
    free(pc->data);
    pc->data = NULL;
}

直接将里面指向有效内容的 pc->data 进行free释放就行,因为它本来就是动态开辟的,后面要有个好习惯,free之后将其置为NULL,不然就为野指针了。

总结:

以上就是动态增容版本通讯录的全部代码,尽管用了动态增容,里面仍然会存在很多的空间浪费,后面等博主学了链表后,在进行改进。

希望这篇文章对大家的学习有所帮助,也希望大家多多支持编程网。

阅读原文内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     813人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     354人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     318人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     435人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     224人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-后端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯