通讯录(C语言)

2023-11-16

结合指针,结构体,枚举,实现增删改查

  1. test.c 用于测试主函数

  1. contact.h 用于函数的声明

  1. contact.c 用于函数的实现

test.c

主要思路:用do-while 实现基本分支结构,并用枚举类型,规定出选择以增加代码可读性

#include "contact.h" 

//通讯录
//1.通讯录中能够存放1000个人的信息
//每个人的信息:
//名字+年龄+性别+电话+地址
//2.增加人的信息
//3.删除指定人的信息
//4.修改指定人的信息
//5.查找指定人的信息
//6.排序通讯录的信息

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

enum Option
{
    EXIT,
    ADD,
    DEL,
    SEARCH,
    MODIFY,
    SORT,
    PRINT
};

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 SORT:
            //排序
            BubbleSortContactByAge(&con);
            break;
        case PRINT:
            //打印
            PrintContact(&con);
            break;
        case EXIT:
            printf("退出通讯录\n");
            break;
        default:
            printf("输入有误\n");
            break;
        }
    } while (input);

    return 0;
}

contact.h

主要思路:定义出联系人类型(PeoInfo),在定义出通讯录类型(Contact),这样就可以清晰的规划联系人的存储,并且可以在通讯录类型里增加联系人人数以方便后面的增删改查操作。可以将其余两个文件共同需要的头文件都引用在这个模块,以实现代码简洁

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

#define MAX_NAME 20
#define MAX_SEX 10
#define MAX_TELE 12
#define MAX_ADDR 30

#define MAX 1000


//类型的定义
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;

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

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

//打印联系人信息
void PrintContact(const Contact *pc);

//删除联系人信息
void DelContact(Contact *pc);

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

//修改指定联系人
void ModifyContact(Contact *pc);

//通过年龄排序
void BubbleSortContactByAge(Contact *pc);

contact.c

初始化 InitContact

这里可以利用memset函数,将pc->data的每个字节设置为0,以实现初始化操作

void InitContact(Contact* pc)
{
    pc->sz = 0;
    //memset(); - 内存设置
    memset(pc->data, 0, sizeof(pc->data));
}

增 AddContact

首先判断通讯录已满情况,确保代码健壮性。最后合理利用通讯录类型(Contact)中的联系人人数,以快速定位通讯录最后,实现增加联系人。注意,age不是数组,所以需要添加取地址操作符(&)。最后将联系人加一

void AddContact(Contact* pc) 
{
    if (pc->sz == MAX) {
        printf("通讯录已满,无法添加");
        return;
    }
    //增加一个人的信息
    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].tele);
    printf("请输入地址:");
    scanf("%s", pc->data[pc->sz].addr);

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

删 DelContact

首先判断通讯录是否为空,以确保代码健壮性。删除联系人主要思路,查->删

所以得实现查找函数(FindByName)同时将查找函数static防止其余文件调用(类似封装性),查找到需要删除的联系人,如果未找到返回-1,否则返回目标联系人下标,这样就可以通过下标实现删除操作,最后联系人减一

static int FindByName(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 DelContact(Contact* pc)
{
    char name[MAX_NAME] = { 0 };
    if (pc->sz == 0) {
        printf("通讯录为空,无需删除\n");
    }
    printf("请输入要删除联系人的名字:\n");
    scanf("%s", name);
    //1.查找要删除的人
    //有or没有
    int pos = FindByName(pc, name);
    if (pos == -1) {
        printf("要删除的人不存在\n");
        return;
    }

    //2.删除
    int i = 0;
    for (i = pos; i < pc->sz-1; i++) {
        pc->data[i] = pc->data[i + 1];
    }

    pc->sz--;
    printf("删除成功\n");
}

改(ModifyContact)

这个函数相对简单,主要思路 查 -> 改

首先因为已经实现了查找函数 (FindByName)可以直接调用,之后的改也和增加联系人的思路相同,注意将下标改为查找函数(FindByName)的返回下标(pos)

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

    printf("请输入要修改联系人的名字:");
    scanf("%s", name);

    int pos = FindByName(pc, name);
    if (pos == -1) {
        printf("要修改的人不存在\n");
        return;
    }
    else {
        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].tele);
        printf("请输入地址:");
        scanf("%s", pc->data[pos].addr);

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

查 (SearchContact)

这里的查(SearchContact)与上面查找函数(FindByName)不同,这个查(SearchContact)是将查找的联系人所有信息打印出来,上面的查找函数(FindByName)则是为了方便增删改查。

主要思路,查 -> 打印

首先还是调用查找函数(FindByName)将需要查找的联系人下标返回,然后再打印出相应的信息,这里可以将字符打印加入固定长度,这样更美观

void SearchContact(Contact* pc)
{
    char name[MAX_NAME] = { 0 };

    printf("请输入要查找联系人的名字:");
    scanf("%s", name);

    int pos = FindByName(pc, name);
    if (pos == -1) {
        printf("要查找的人不存在\n");
        return;
    }
    else {
        //打印标题
        printf("%-20s\t%-5s\t%-5s\t%-12s\t%-20s\n", "名字", "年龄", "性别", "电话", "地址");
        //打印数据
        printf("%-20s\t%-5d\t%-5s\t%-12s\t%-20s\n",
            pc->data[pos].name,
            pc->data[pos].age,
            pc->data[pos].sex,
            pc->data[pos].tele,
            pc->data[pos].addr);
    }
}

打印PrintContact

这个函数很简单,利用for循环打印即可,循环条件为联系人人数

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

排序BubbleSortContactByAge

这里的排序就是经典的冒泡排序,通过年龄。

主要思路:遍历数组,如果第i个元素 大于 第i+1个元素,则将两个通过tmp遍历互换位置,实现升序

降序也一样,只需要将 大于 改成 小于即可。

冒泡排序难以理解的应该就是两个循环的循环条件,其中的 (数组长度 - 1)就是 冒泡排序需要排序几趟,因为当数组排序到只剩最后一个元素则不需要再排序,所以需要 -1。(数组长度 - i - 1)则是一趟排序, 因为每一趟排序后,后面就已经固定了一些数(也就是已经排序好了),因为冒泡排序就是将最大或最小的元素送到数组的最左端或最右端,所以就每排序一趟,就会有一个元素不用排序,左移排序i趟,就会有i个元素不用排序,所以内层循环的循环条件是(数组长度 - i - 1)。(第一次接触排序的童鞋)这里最好画画图帮助理解。

void BubbleSortContactByAge(Contact* pc) 
{
    int k = 0;
    PeoInfo tmp = {0};
    printf("请选择升序还是降序(1:升序, 2:降序):");
    scanf("%d", &k);
    if (k == 1) {
        int i = 0;
        for (i = 0; i < pc->sz - 1; i++) {
            int j = 0;
            for (j = 0; j < pc->sz - i - 1; j++) {
                if (pc->data[j].age > pc->data[j + 1].age) {
                    tmp = pc->data[j+1];
                    pc->data[j+1] = pc->data[j];
                    pc->data[j] = tmp;
                }
            }
        }

        printf("排序成功,信息为升序\n");
    }
    else if (k == 2) {
        int i = 0;
        for (i = 0; i < pc->sz - 1; i++) {
            int j = 0;
            for (j = 0; j < pc->sz - i - 1; j++) {
                if (pc->data[j].age < pc->data[j + 1].age) {
                    tmp = pc->data[j + 1];
                    pc->data[j + 1] = pc->data[j];
                    pc->data[j] = tmp;
                }
            }
        }

        printf("排序成功,信息为降序\n");
    }
    else {
        printf("输入有误\n");
    }
}

代码全貌

#include "contact.h"

void InitContact(Contact* pc)
{
    pc->sz = 0;
    //memset(); - 内存设置
    memset(pc->data, 0, sizeof(pc->data));
}

void AddContact(Contact* pc) 
{
    if (pc->sz == MAX) {
        printf("通讯录已满,无法添加");
        return;
    }
    //增加一个人的信息
    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].tele);
    printf("请输入地址:");
    scanf("%s", pc->data[pc->sz].addr);

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

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

static int FindByName(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 DelContact(Contact* pc)
{
    char name[MAX_NAME] = { 0 };
    if (pc->sz == 0) {
        printf("通讯录为空,无需删除\n");
    }
    printf("请输入要删除联系人的名字:\n");
    scanf("%s", name);
    //1.查找要删除的人
    //有or没有
    int pos = FindByName(pc, name);
    if (pos == -1) {
        printf("要删除的人不存在\n");
        return;
    }

    //2.删除
    int i = 0;
    for (i = pos; i < pc->sz-1; i++) {
        pc->data[i] = pc->data[i + 1];
    }

    pc->sz--;
    printf("删除成功\n");
}

void SearchContact(Contact* pc)
{
    char name[MAX_NAME] = { 0 };

    printf("请输入要查找联系人的名字:");
    scanf("%s", name);

    int pos = FindByName(pc, name);
    if (pos == -1) {
        printf("要查找的人不存在\n");
        return;
    }
    else {
        //打印标题
        printf("%-20s\t%-5s\t%-5s\t%-12s\t%-20s\n", "名字", "年龄", "性别", "电话", "地址");
        //打印数据
        printf("%-20s\t%-5d\t%-5s\t%-12s\t%-20s\n",
            pc->data[pos].name,
            pc->data[pos].age,
            pc->data[pos].sex,
            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;
    }
    else {
        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].tele);
        printf("请输入地址:");
        scanf("%s", pc->data[pos].addr);

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

void BubbleSortContactByAge(Contact* pc) 
{
    int k = 0;
    PeoInfo tmp = {0};
    printf("请选择升序还是降序(1:升序, 2:降序):");
    scanf("%d", &k);
    if (k == 1) {
        int i = 0;
        for (i = 0; i < pc->sz - 1; i++) {
            int j = 0;
            for (j = 0; j < pc->sz - i - 1; j++) {
                if (pc->data[j].age > pc->data[j + 1].age) {
                    tmp = pc->data[j+1];
                    pc->data[j+1] = pc->data[j];
                    pc->data[j] = tmp;
                }
            }
        }

        printf("排序成功,信息为升序\n");
    }
    else if (k == 2) {
        int i = 0;
        for (i = 0; i < pc->sz - 1; i++) {
            int j = 0;
            for (j = 0; j < pc->sz - i - 1; j++) {
                if (pc->data[j].age < pc->data[j + 1].age) {
                    tmp = pc->data[j + 1];
                    pc->data[j + 1] = pc->data[j];
                    pc->data[j] = tmp;
                }
            }
        }

        printf("排序成功,信息为降序\n");
    }
    else {
        printf("输入有误\n");
    }
}

总结

这个通讯录可以很好的练到指针和结构体,是个很好的练手小项目,这也可以通过链表及顺序表实现,这样就可以练到数据结构的线性表。后续会写一个链表版本的。用来练习链表

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

通讯录(C语言) 的相关文章

随机推荐

  • python3 with.py

    模块 python3 with py 参考 https docs python org zh cn 3 reference compound stmts html with https docs python org zh cn 3 ref
  • 关于海量用户访问的通用技术架构的一些思考

    最近12306 cn网站事件引起了很多人对架构的思考 这种访问量巨大的网站究竟该如何来做架构 下面是我的想法 因为要考虑到通用抛开业务单纯从技术层面分析 要承载海量用户的访问 要求网站高性能和高可用 安全可靠 高可收缩性 易于维护 等等一堆
  • 20道常见的kafka面试题以及答案

    JAVA面试宝典 搞定JAVA面试 不再是难题 系列文章传送地址 请点击本链接 目录 1 kafka的消费者是pull 拉 还是push 推 模式 这种模式有什么好处 2 kafka维护消息状态的跟踪方法 3 zookeeper对于kafk
  • jq微信账号正则表达式

    微信号官方规则 必须以字母或下划线开头 可以使用6 20位数字 字母 下划线 减号或它们的组合 正则表达式 a zA Z a zA Z0 9 6 20 如有其它问题欢迎大家留言
  • excel批量提取多个文件单元格_EXCEL高手专用函数Indirect,快速提取多个工作表,特定单元格数据...

    Indirect间接引用函数 你应学会的跨表引用技能 点关注 交朋友 大家共同学技术 几天前 看到有人问 excel中有哪些技能是你以前不知道 但是后来知道了却一直没有忘记的 我首先想到了 Indirect函数 使我的工作效率提高了百倍 千
  • vue常用知识总结

    vue常用知识总结 vue简介 vue 响应式原理 Object defineProperty vue 的作者 尤雨溪 java 出身 vue 是什么 以数据驱动视图的单页面 spa 渐进式 MVVM 框架 特性 数据双向绑定 模块化开发
  • Embarcadero Dev-C++第一次使用注意事项

    Embarcadero Dev C 第一次使用注意事项 Embarcadero Dev C 简介 2000年左右 Bloodshed software开发了Dev C 提供轻量 免费 开源的C C IDE Dev C 是最适合初学C 语言的
  • 基于stm32单片机自动灭火火灾报警装置Proteus仿真

    资料编号 102 下面是相关功能视频演示 102 基于stm32单片机自动灭火火灾报警装置Proteus仿真 仿真 源码 全套资料 功能介绍 火焰传感器的原理 是通过感知外部特殊波段光照强度的突变来判断是否出现火灾 该仿真采用ADC采集光照
  • Maven 知识点总结

    文章目录 Maven 1 Maven 坐标 2 Maven 仓库 3 Maven 依赖 依赖配置 依赖范围 依赖调解原则 排除依赖 4 Maven 生命周期 5 Maven 聚合与继承 Maven Maven是一个项目管理工具 它包含了项目
  • c# MACD 算法实现

    此算法在自己WP7应用中 用到 同花顺 算法 DIFF EMA CLOSE SHORT EMA CLOSE LONG DEA EMA DIFF M MACD 2 DIFF DEA Zero 0 关键点是第一天的数据 如果是区间的数据 区间第
  • Bootstrap弹出模态框

    弹出模态框 Modal 使用Bootstrap的JavaScript模态框插件可以为您的网站添加醒目的提示和交互 用于通知用户 访客交互 消息警示或自定义的内容交互 如考试问答场景 译者注 运行原理 在开始使用Bootstrap模态框组件前
  • CMDB功能分析与实现方案

    CMDB功能分析与实现方案 CMDB系统的主要功能 1 用户管理 记录测试 开发 运维人员的用户表 2 业务线管理 记录业务的详情 3 项目管理 指定此项目属于那一条业务线 4 应用管理 指定此应用的开发人员 5 主机管理 记录主机管理员
  • 软件项目管理和实施方案

    一 实施周期 自合同签订或约定之日起xxx个日历日内完成项目需求调研 软件开发及调试工作 实现系统上线运行 并完成项目验收 二 项目进度 一 项目计划 根据本公司对项目建设工期的整体计划 本公司将整个系统的建设工作按照计划进行详细分工 把任
  • PCL-OpenCV冲突的解决方案

    测试LIO SAM 编译期报错 error field param k has incomplete type flann SearchParams 查了github 把 usr include pcl 1 7 pcl kdtree kdt
  • Dialog的弹出位置控制

    Dialog一般出现都是屏幕中心 但有的时候我们希望它能在屏幕左侧 或者右侧亦或者是屏幕顶部 这时候我们就需要用的Dialog getWindow getAttributes 方法啦 dialog new Dialog getActivit
  • Qwt使用总结,初步整理

    最近研究了一些Qwt 至此总结Qwt的认识以便以后的备忘 从什么方面开始说起呢 从这个类是什么 可以用来做什么 关于Qwt的简介就不说了 主要说说其中用到的几个类吧 QwtPlot 是一个2D画图控件 Widget 继承于QFram和Qwt
  • Mybatis Plus 3.1.0枚举类处理器重写TypeHandler

    我的环境 Springboot 2 13 Mybatis Plus 3 1 Oracle 11g 驱动版本oracle6 1 我尝试用 Mybatis Plus 3 1 以上版本 如 3 2 3 3 时 oracle6 驱动无法适配 2 枚
  • JAVA线程的中断

    每个线程都有一个boolean类型的标志来表明线程是否发生了中断 并且包含了中断相关的函数 interrupt 用于设置线程的中断状态为true isInterrupted 用于返回线程的中断状态 interrupted 方法用于清除中断状
  • cast函数_QT槽函数获取信号发送对象

    Qt 在槽函数中获取信号发送对象 Qt中提供了一个函数 qobject cast QObject object 可以通过这个函数判断信号发出对象 Qt 帮助文档的解释 Returns the given object cast to typ
  • 通讯录(C语言)

    结合指针 结构体 枚举 实现增删改查 test c 用于测试主函数 contact h 用于函数的声明 contact c 用于函数的实现 test c 主要思路 用do while 实现基本分支结构 并用枚举类型 规定出选择以增加代码可读