c++vscode多文件实现通讯录管理系统

news2024/11/12 5:57:04

c++vscode多文件实现通讯录管理系统

作为c++入门级别的实战项目,此通讯管理系统项目不仅仅是对c++入门阶段学习成果的检验,也是对c++基础知识的回顾,体会c++在实战制作中的思路,是入门c++单文件实现通讯录系统的改进

img

在这里插入图片描述

一、多文件通讯录管理系统简介

系统需求通讯录是一个可以记录亲人、好友信息的工具。

本教程主要利用C++来实现一个通讯录管理系统系统中需要实现的功能如下:

  • 添加联系人:向通讯录中添加新人,信息包括(姓名、性别、年龄、联系电话、家庭住址)最多记录1000人
  • 显示联系人:显示通讯录中所有联系人信息
  • 删除联系人:按照姓名进行删除指定联系人
  • 查找联系人:按照姓名查看指定联系人信息
  • 修改联系人:按照姓名重新修改指定联系人
  • 清空联系人:清空通讯录中所有信息
  • 退出通讯录:退出当前使用的通讯录

相对于原先通讯录管理系统优化之处:

  1. 添加读取文件保存进独立文件功能,记录,使下次运行时保存原先的联系人
  2. 多文件协同运行,包括头文件.h和文件.cpp
  3. 可以批量添加多人

二、思路

image-20240830211437479

三、功能实现

3.1 person.h封装

image-20240830211756354

#pragma once // 防止文件重复
#include <iostream>
#include <string>
using namespace std;
class Person
{
public:
    string Name;    // 联系人姓名
    int Age;        // 联系人年龄
    int Sex;        // 联系人性别,后续1表示男,2表示女
    string Address; // 联系人地址
    string Phone;   // 联系人电话
    Person();
    // 初始化人
    Person(string name, int age, int sex, string phone, string address);
};

person.cpp实现如下:

#include "person.h"
Person::Person()
{
}
Person::Person(string name, int age, int sex, string phone, string address)
{
    Name = name;
    Age = age;
    Sex = sex;
    Phone = phone;
    Address = address;
}

3.2 manager.h类封装

image-20240830212420597

#pragma once // 防止文件重复
#include <iostream>
#include <string>
using namespace std;
#include "person.h"
#define MAX 1000//便于后期维护
#define FILE_NAME "person.txt"//便于后期维护
class Manager
{
public:

    Person arr[MAX]; // 创建一个z最大能容纳1000个人的数组
    int num;         // 记录当前有多少人

    // 构造函数,判断文件状态
    Manager();

    // 得到原先文件联系人数量
    int getNum();

    // 初始化程序
    void init();

    // 读取保存文件
    void save();

    // 显示菜单
    void showMenu();

    // 退出功能
    void Exit();

    // 添加联系人功能
    void addPerson();

    // 创建判断文件是否为空的标志,以便查看联系人功能实现
    bool isEmpty = false;

    // 添加查看联系人功能
    void showPerson();

    // 删除联系人功能
    void deletePerson();

    // 查找联系人功能
    void findPerson();

    // 修改联系人功能
    void modifyPerson();

    // 清空联系人功能
    void clearPerson();
};

成员行为实现:(manager.cpp内容)

  1. 显示菜单:void showMenu()
// 实现展示菜单功能
void Manager::showMenu()
{
    cout << "*************************" << endl;
    cout << "***** 1、添加联系人 *****" << endl;
    cout << "***** 2、显示联系人 *****" << endl;
    cout << "***** 3、删除联系人 *****" << endl;
    cout << "***** 4、查找联系人 *****" << endl;
    cout << "***** 5、修改联系人 *****" << endl;
    cout << "***** 6、清空联系人 *****" << endl;
    cout << "***** 0、退出通讯录 *****" << endl;
    cout << "*************************" << endl;
}
  1. 得到原来保存联系人数量:void getNum(),在第四步会用到
// 得到原先文件联系人数量
int Manager::getNum()
{
    ifstream ifs;
    ifs.open(FILE_NAME, ios::in);
    int num = 0;
    string name;    // 联系人姓名
    int age;        // 联系人年龄
    int sex;        // 联系人性别,后续1表示男,2表示女
    string address; // 联系人地址
    string phone;   // 联系人电话
    
    //当人的所有属性被读取到后才可进行num++
    while (ifs >> name && ifs >> sex && ifs >> age && ifs >> phone && ifs >> address)
    {
        num++;
    }
    ifs.close();
    return num;
}
  1. 初始化函数:void init()(使通讯录功能正常使用,读取之前保存在person.txt文件中的数据,在第四步也会用到)
// init功能
void Manager::init()
{
    ifstream ifs;
    ifs.open(FILE_NAME, ios::in);
    string name;    // 联系人姓名
    int age;        // 联系人年龄
    int sex;        // 联系人性别,后续1表示男,2表示女
    string address; // 联系人地址
    string phone;   // 联系人电话

    int index = 0;
    while (ifs >> name && ifs >> sex && ifs >> age && ifs >> phone && ifs >> address)
    {
        this->arr[index] = Person(name, sex, age, phone, address);
        index++;
    }
}
  1. 读文件:Manager()(Manager类的默认构造函数,会用到上一步的getNum())
// 文件读取
Manager::Manager()
{
    // 1.文件未创建
    ifstream ifs;
    ifs.open(FILE_NAME, ios::in);
    if (!ifs.is_open())
    {
        isEmpty = true;//文件是否为空标志,是
        this->num = 0;
        ifs.close();
        return;
    }
    // 2.文件创建但数据为空
    char ch;
    ifs >> ch;
    if (ifs.eof())
    {
        isEmpty = true; // 文件是否为空标志,是
        this->num = 0;
        ifs.close();
        return;
    }
    // 3. 文件存在且数据不为空,以既有数据初始化程序
    isEmpty = false; // 文件是否为空标志,不是
    
    this->num = this->getNum();//得到原来保存联系人数量,即第二步
    
    this->init();//初始化,即第三步
}
  1. 保存已录入数据:void save()(后面大部分功能都将用到此函数)
// 实现文件写入保存功能
void Manager::save()
{
    ofstream ofs;
    ofs.open(FILE_NAME, ios::out);
    for (int i = 0; i < this->num; i++)
    {
        ofs << this->arr[i].Name << " "
            << this->arr[i].Sex << " "
            << this->arr[i].Age << " "
            << this->arr[i].Phone << " "
            << this->arr[i].Address << endl;
    }
    ofs.close();
}
七大功能实现
  1. 退出功能
// 实现退出功能
void Manager::Exit()
{
    cout << "欢迎下次使用" << endl;
    exit(0);
}
  1. 添加联系人功能:void addPerson()(添加并同时保存到数组中,再利用save()保存在文件中,实现了一次添加多人功能)
// 实现添加联系人功能
void Manager::addPerson()
{
    if (num == 1000)
    {
        cout << "通讯录已满,无法添加" << endl;
        return;
    }
    // 批量添加
    cout << "请输入添加联系人的数量:" << endl;
    int addNum; // 要添加的数量
    cin >> addNum;
    int i = 1;//从第一个人开始添加
    while (addNum) // 循环添加
    {

        // 添加姓名
        string name;
        cout << "请输入第" << i << "名联系人姓名:" << endl;
        cin >> name;
        arr[num].Name = name;//num即上次关闭程序保存的人数,此次添加就从其后添加

        // 添加年龄
        int age;
        cout << "请输入联系人年龄:" << endl;
        cin >> age;
        arr[num].Age = age;

        // 添加性别
        int sex;
        cout << "请选择联系人性别:" << endl;
        cout << "1.男" << endl;
        cout << "2.女" << endl;
        cin >> sex;
        if (sex == 1)
        {
            arr[num].Sex = 1;
        }
        else
        {
            arr[num].Sex = 2;
        }

        // 添加电话
        string phone;
        cout << "请输入联系人电话:" << endl;
        cin >> phone;
        arr[num].Phone = phone;

        // 添加地址
        string address;
        cout << "请输入联系人地址:" << endl;
        cin >> address; 
        arr[num].Address = address;
        
        i++;//下一个人
        num++;
        addNum--;//想要添加的人数即减一
        cout << "添加成功" << endl;
        this->save();
        // 更新职工不为空的标志
        this->isEmpty = false;
    }
}
  1. 显示联系人功能:void showPerson()
// 实现显示联系人功能
void Manager::showPerson()
{

    if (this->isEmpty)
    {
        cout << "通讯录为空" << endl;
        return;
    }
    for (int i = 0; i < this->num; i++)
    {
        cout << "姓名:" << this->arr[i].Name << "\t";
        if (this->arr[i].Sex == 1)
        {
            cout << "性别:男" << "\t";
        }
        else
        {
            cout << "性别:女" << "\t";
        }
        cout << "年龄:" << this->arr[i].Age << "\t";
        cout << "电话:" << this->arr[i].Phone << "\t";
        cout << "地址:" << this->arr[i].Address << "\t" << endl;
    }
}
  1. 删除联系人功能:void deletePerson()(实质是数据前移)
// 实现删除联系人功能
void Manager::deletePerson()
{
    if (this->isEmpty)
    {
        cout << "通讯录为空" << endl;
        return;
    }
    cout << "请输入要删除的联系人姓名:" << endl;
    string name;
    cin >> name;

    int temp = num;
    for (int i = 0; i < temp; i++)
    {
        if (this->arr[i].Name == name)
        {
            for (int j = i; j < this->num - 1; j++)
            {
                this->arr[j] = this->arr[j + 1];
            }
            this->num--;
        }
       
    }
    if (this->num == temp)
    {
        cout << "没有找到该联系人" << endl;
    }else{
        cout << "删除成功" << endl;
    }
    this->save();
}
  1. 查找联系人功能:void findPerson()(根据姓名查找)
// 实现查找联系人功能
void Manager::findPerson()
{
    if (this->isEmpty)
    {
        cout << "通讯录为空" << endl;
        return;
    }
    cout << "请输入要查找的联系人姓名:" << endl;
    string name;
    cin >> name;
    for (int i = 0; i < this->num; i++)
    {
        if (this->arr[i].Name == name)
        {
            cout << "姓名:" << this->arr[i].Name << "\t";
            if (this->arr[i].Sex == 1)
            {
                cout << "性别:男" << "\t";
            }
            else
            {
                cout << "性别:女" << "\t";
            }
            cout << "年龄:" << this->arr[i].Age << "\t";
            cout << "电话:" << this->arr[i].Phone << "\t";
            cout << "地址:" << this->arr[i].Address << "\t" << endl;
        }
        if (i == this->num - 1)
        {
            cout << "未找到该联系人" << endl;
            return;
        }
    }
    cout << "查找成功" << endl;
}
  1. 修改联系人功能:void modifyPerson()
  • 根据姓名修改,首先先显示所有此姓名的人,再从中选择要修改的人
  • 再用Person定义一个临时数组,记录同名的人,根据下标选择想要修改的人
  • 通过比较临时数组中的联系人和通讯录中的联系人来找到要修改的联系人的索引
// 实现修改联系人功能
void Manager::modifyPerson()
{
    if (this->isEmpty)
    {
        cout << "通讯录为空" << endl;
        return;
    }
    cout << "选择你要修改的联系人的姓名:" << endl;
    string name;
    cin >> name;
    Person temp[MAX]; // 用Person定义一个小数组,记录同名的人,根据下标选择想要修改的人
    int index = 0;
    for (int i = 0; i < this->num; i++)
    {

        if (arr[i].Name == name)
        {
            cout << "姓名:" << this->arr[i].Name << "\t";
            if (this->arr[i].Sex == 1)
            {
                cout << "性别:男" << "\t";
            }
            else
            {
                cout << "性别:女" << "\t";
            }
            cout << "年龄:" << this->arr[i].Age << "\t";
            cout << "电话:" << this->arr[i].Phone << "\t";
            cout << "地址:" << this->arr[i].Address << endl;
            temp[index] = arr[i];
            index++;
        }
        if (i == this->num - 1)
        {
            cout << "未找到该联系人" << endl;
            return;
        }
    }
    cout << "请选择要修改的联系人的序号:" << endl;
    int NUM;
    cin >> NUM;
    int newIndex;
    for (int i = 0; i < num; i++)
    {
        if (temp[NUM - 1].Name == arr[i].Name && temp[NUM - 1].Phone == arr[i].Phone && temp[NUM - 1].Address == arr[i].Address && temp[NUM - 1].Age == arr[i].Age && temp[NUM - 1].Sex == arr[i].Sex)
        {
            newIndex = i; // 找到了要修改的联系人的下标
        }
    }
    cout << "请输入修改后的联系人姓名:" << endl;
    string newName; // 因为上面已经定义了name,所以这用newName,防重复
    cin >> newName;
    arr[newIndex].Name = newName;
    cout << "请输入修改后的联系人性别:" << endl;
    cout << "1.男" << endl;
    cout << "2.女" << endl;
    int sex;
    cin >> sex;
    if (sex == 1)
    {
        arr[newIndex].Sex = 1;
    }
    else
    {
        arr[newIndex].Sex = 2;
    }
    cout << "请输入修改后的联系人年龄:" << endl;
    int age;
    cin >> age;
    arr[newIndex].Age = age;
    cout << "请输入修改后的联系人电话:" << endl;
    string phone;
    cin >> phone;
    arr[newIndex].Phone = phone;
    cout << "请输入修改后的联系人地址:" << endl;
    string address;
    cin >> address;
    arr[newIndex].Address = address;
    cout << "修改成功" << endl;
    this->save();
}
  1. 清空通讯录功能
// 清空联系人功能
void Manager::clearPerson()
{
    if (this->isEmpty)
    {
        cout << "通讯录为空" << endl;
        return;
    }
    cout << "确定清空通讯录吗?" << endl;
    cout << "1.确定" << endl;
    cout << "2.取消" << endl;
    int choice;
    cin >> choice;
    if (choice == 1)
    {
        this->num = 0;
        this->isEmpty = true;
        this->save();
        cout << "清空成功" << endl;
    }
    else
    {
        cout << "取消成功" << endl;
    }
}

到此即实现了完整的通讯录管理系统

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2090595.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

JAVA—多线程

关于线程以及多线程的学习&#xff0c;包括创建和常用方法还有解决线程安全的措施&#xff0c;最后学习线程池和了解并发和并行&#xff0c;对于悲观锁和乐观锁的部分没有学习 目录 1.线程概述 2.多线程的创建 &#xff08;1&#xff09;继承Thread类 &#xff08;2&#…

【GPT】基于GPT_API_free做一个自己的gpt

最终效果 项目背景 秉持能免费就绝不花钱的原则&#xff0c;基于github项目GPT_API_free获取的gpt apikey。下面是简单的代码 import json import os import requestsopenai_url os.getenv("openaiproxy") openai_apikey os.getenv("openaikey") # 初始…

[图解]SysML和EA建模住宅安全系统-活动作为块

1 00:00:00,210 --> 00:00:04,360 下一个步骤是识别潜在的失效 2 00:00:06,850 --> 00:00:11,150 这里它是用一个块定义图来表达的 3 00:00:12,150 --> 00:00:16,790 图17.21&#xff0c;失效模式识别和因果依赖 4 00:00:19,110 --> 00:00:22,400 但是这个块定义…

【AutoX.js】定时器 Timers

文章目录 原文&#xff1a;https://blog.c12th.cn/archives/36.html定时器 Timers笔记实例 最后 原文&#xff1a;https://blog.c12th.cn/archives/36.html 定时器 Timers 笔记 JavaScript Date 参考手册 时间戳 //当前时间戳 log(Math.round(new Date() / 1000));当前星期 …

C语言小tip之函数递归

hello&#xff0c;各位小伙伴们今天我们来学习一下函数递归。 什么是函数递归呢&#xff1f;简单来说就是函数自己来调用自己。函数递归的主要思想是把大事化小&#xff0c;递归包含两层方面&#xff1a;1、递推 2、回归 在使用函数递归的时候要注意包含两个限制条件&#…

SCI英文期刊发表流程

目录 一、撰写初稿二、预审三、英文查重四、Cover letter和Highlights五、英文语法待续 一、撰写初稿 英文好的话应该直接写英文&#xff0c;因为中英文的写法不一样。 而且在这一步把格式修改好&#xff0c;初稿的最终版 二、预审 可以让同学、老师帮看论文&#xff0c;或者…

[Algorithm][综合训练][字符编码][最少的完全平方数][游游的字母串]详细讲解

目录 1.字符编码1.题目链接2.算法原理详解 && 代码实现 2.最少的完全平方数1.题目链接2.算法原理详解 && 代码实现 3.游游的字母串1.题目链接2.算法思路详解 && 代码实现 1.字符编码 1.题目链接 字符编码 2.算法原理详解 && 代码实现 解法&…

Carla自动驾驶仿真十:Carlaviz三维可视化平台搭建

文章目录 前言一、环境准备1、docker安装2、websocket-client安装3、carlaviz代码下载 二、carlaviz使用1、打开carla客户端2、输入启动命令3、进入carlaviz4、修改manual_control.py脚本5、运行manual_control.py脚本6、运行carlaviz官方脚本&#xff08;推荐&#xff09; 前言…

数据库之心:MySQL 探索(一)mysql的安装和基本介绍

欢迎来到我们的MySQL博客&#xff01;在这里&#xff0c;我们将深入探讨MySQL数据库系统的各个方面&#xff0c;包括基础知识、优化技巧、实践案例以及最新的行业趋势。 目录 前言 什么是数据库&#xff1f; 数据库产品 MySQL安装 解压 配置 添加环境变量 初始化MySQL …

计算机毕业设计PySpark+Scrapy高考推荐系统 高考志愿填报推荐系统 高考爬虫 协同过滤推荐算法 Vue.js Django Hadoop 大数据毕设

目  录 第1章 绪论 1.1 研究背景 1.2 国内外现状 1.2.1 国外研究现状 1.2.2 国内研究现状 1.3 主要研究内容 1.4 论文框架结构 第2章 相关开发技术与理论 2.1 前端技术 1&#xff0e;Vue框架技术 2&#xff0e;Element-Plus 2.2 后端技术 1&#xff0e…

linux下cpu多核运行程序以及运行时间统计

一、多核心运行程序 在linux下我们可以指定线程或者进程运行在指定的cpu核心上&#xff0c;操作方法如下&#xff1a; 1&#xff09;运行进程指定cpu核心 taskset -c 2 ./app //-c指定运行的cpu核心号&#xff0c;从0计数&#xff0c;查看效果如下&#xff1a; 2&#xff09…

C++map容器中operator[ ]的实现原理

目录 一、operator[ ]函数介绍 二、insert函数介绍 三、operator[ ]函数实现原理 四、operator[ ]函数功能 一、operator[ ]函数介绍 mapped_type& operator[] (const key_type& k);在map容器中存储的是一个键值对value_type&#xff0c;其本质是pair<const key…

maya python调试(pycharm)

maya里面调试代码一直用的print。遇到复杂点的类就感觉有点束手束脚的&#xff0c;因此整理了一下maya调试的一些方法 1.万能的pdb调试 pdb 有2种用法 1.非侵入式方法 &#xff08;不用额外修改源代码&#xff0c;在命令行下直接运行就能调试&#xff09; 常规用法&#xf…

APP长文本内容编辑器功能实现方案

背景 CSDN APP 中原有编辑器页面为纯H5适配&#xff0c;整体用户交互体验差&#xff0c;如何优化APP端编辑器用户体验是我们团队需要思考的问题。下面我们以iOS为例展开讨论。 一、方案调研 我们分析了几款国内内容发布的APP&#xff0c;如知乎、今日头条、简书&#xff0c;…

有了它 一键掌握Vue新版本!

声明&#xff1a;此篇为 ai123.cn 原创文章&#xff0c;转载请标明出处链接&#xff1a;https://ai123.cn/#1 你是否也在为Vue生态中的快速更新而焦头烂额&#xff1f;ue 3.4版本发布&#xff0c;带来模板解析器重写和响应系统重构&#xff0c;提升了性能和开发体验。测试框架如…

《深入理解JAVA虚拟机(第2版)》- 第3章 - 学习笔记

第3章 垃圾收集器与内存分配策略 3.1 概述 垃圾收集器要完成三件事情&#xff1a; 什么样的内存需要回收什么时候回收如何回收 垃圾收集器主要关注的区域是&#xff1a;Java堆和方法区。因为程序计数器、虚拟机栈、本地方法栈是线程私有的&#xff0c;随着线程的结束所使用的…

2d椭圆拟合学习

算法来自论文《 Direct Least Square Fitting of Ellipses》 《NUMERICALLY STABLE DIRECT LEAST SQUARES FITTING OF ELLIPSES》 相关文章 论文阅读&#xff1a;直接拟合椭圆 Direct Least Square Fitting of Ellipseshttps://zhuanlan.zhihu.com/p/645391510Fitting Elli…

rsyslog交叉编译

文章目录 1、依赖库列表2、编译建议3、编译3.1、编译libestr3.2、编译libfastjson3.3、编译zlib3.4、编译libuuid3.5、编译libgpg-error3.6、编译libgcrypt3.7、编译openssl3.8、编译curl3.9、编译rsyslog该文档描述了如何交叉编译rsyslog到arm64嵌入式平台。 1、依赖库列表 li…

UE5开发——射击武器类拾取

整体框架&#xff1a; 拾取武器 要在 Unreal Engine 5 (UE5) 中实现一个按 E 键拾取武器的功能&#xff0c;您可以遵循以下步骤&#xff1a; ### 步骤 1: 创建拾取物品的基础类 1. 在 Content Browser 中创建一个新的 C 类&#xff0c;继承自 AActor 或者 AStaticMeshActor。…

pytorch交叉熵损失函数

nn.CrossEntropyLoss 是 PyTorch 中非常常用的损失函数,特别适用于分类任务。它结合了 nn.LogSoftmax 和 nn.NLLLoss(负对数似然损失)的功能,可以直接处理未经过 softmax 的 logits 输出,计算预测值与真实标签之间的交叉熵损失。 1. 交叉熵损失的原理 交叉熵损失衡量的是…