一款基于c++的可以满足基础的查看、添加、删除、修改、清空联系人的程序,适合新手练习。
编码环境,visual studio 2022,c++空项目
需求分析:
拿到问题后,首先进行需求分析,一款c++程序,可以存储一些联系人信息,并在需要的时候输出信息。
第一个问题,用什么存储信息?
经过我搜集各类资料后,选择了我认为最简单的文件(.txt),也就是可以通过c++标准库函数fstream进行文件流的写入、读取、更改等操作。
第二个问题,程序主体应该怎么写?
首先,头文件添加最基础的iostream和需要输出string类型的string和using namespace std;
#include<iostream>
#include<string>
using namespace std;
其次,我们根据需求输出一个菜单与用户进行交互,接收到用户所选择的功能然后执行。那么switch选择语句在这里就最为使用。
#include<iostream>
#include<string>
using namespace std;
int main()
{
cout << "菜单" << endl;
int i;
cin >> i;
switch (i)
{
case 1:
//查看
break;
case 2:
//添加
break;
case 3:
//删除
break;
case 4:
//修改
break;
case 5:
//清空
break;
case 0:
//退出
break;
default:
//输入数字错误
break;
}
return 0;
}
然后,我们如何让这个行为(输出菜单,接收用户需求,执行)不停的重复直到用户想要退出程序呢?循环语句while!在此时就很适合。我们将整个行为的代码放入while循环中,再设置用户选择退出的条件为循环结束条件就完成了我们的设想。
再加入一些文字提示用户操作。
#include<iostream>
#include<string>
using namespace std;
int main()
{
bool flag = true;//标志位
while (flag)
{
cout << "菜单" << endl;
int i;
cin >> i;
switch (i)
{
case 1:
//查看
break;
case 2:
//添加
break;
case 3:
//删除
break;
case 4:
//修改
break;
case 5:
//清空
break;
case 0:
//退出
flag = false;//当用户选择0.即想要退出程序时,将标志位置0,循环结束
cout << "欢迎下次使用!!!" << endl;
break;
default:
//输入数字错误
cout << "您的输入有误,请重新选择功能对应数字输入:" << endl;
break;
}
}
return 0;
}
此时经过运行,发现程序已经可以正常运作,我们的初步目的已经达到。
第三个问题,功能的实现应该怎么构造函数?
首先还是先来看看我们的需求:
- 打印菜单并接收用户输入反馈给switch
- 查看通讯录
- 添加联系人
- 删除联系人
- 修改联系人信息
- 清空通讯录
其中,我们多次用到联系人,他应该包含姓名、性别、住址、电话号码等多种信息,所以构造一个struct结构体是很有用的。
考虑到后续需要写入txt文件中并且并无特殊需求,那么其中信息都可以用string类型进行存储。
struct people
{
string name;
string gender;
string address;
string phoneNumber;
};
然后在主函数前声明函数:
int show_menu();//显示菜单
void read_line();//查看通讯录
void add_people();//添加
void delete_people();//删除
void modify_people();//修改
void clear_people();//清空
之后逐一完善函数功能在主函数后方,此时根据需求在头部添加头文件:
#include<iostream>
#include<fstream>
#include<locale>
#include<string>
1.菜单:
打印需求和对应的功能,接收用户输入数字并返回给switch,自然返回值类型为int,并添加一些文字提示:
int show_menu()
{
cout << "~~~~~~~~~~~~~~~欢迎使用通讯录管理系统~~~~~~~~~~~~~~~" << endl;
cout << "\t1----显示所有联系人" << endl;
cout << "\t2----添加联系人" << endl;
cout << "\t3----删除联系人" << endl;
cout << "\t4----修改联系人" << endl;
cout << "\t5----清空联系人列表" << endl;
cout << "\t0----退出系统" << endl;
cout << "请您输入选项所对应的数字:" << endl;
int i = 0;
cin >> i;
return i;
}
修改主函数switch语句条件为:
int main()
{
bool flag = true;
while (flag)
{
switch (show_menu())
{
case 1://省略
2.查看通讯录:
查看通讯录是需要我们读取txt文件,并输出,这里我们按行读取:
void read_line()
{
//txt文件路径含有中文字符,所以需要一个宽字符串变量wstring来记录,名为filePath,使用L表示引号内为宽字符串,双斜杠用以转义,否则会出错
wstring filePath = L"D:\\study C++\\通讯录系统\\联系人目录.txt";
ifstream file(filePath);//定义一个ifstream(读取流)的对象file用于后续调用函数,打开文件,()内为路径
if (file.is_open())//判断是否打开
{
string line;//定义一个字符串用于接收读取到的字符串
while (getline(file, line))按行读取后暂时存入line中
{
cout << line << endl;//打印并换行
}
file.close();//关闭文件,释放资源
cout <<"完成读取!!!"<< endl;//提示读取成功
}
else cout << "无法打开文件!!!" << endl;//文件打开失败时提示
}
3.添加联系人
注意,我们是通过程序作为一个入口和路径最终达到修改txt文件的用法。
void add_people()
{
//依旧是按行添加,首先接收用户输入的关于联系人的所有信息
people x;
cout << "请按照提示输入联系人的相关信息" << endl;
cout << "姓名:";
cin >> x.name;
cout << endl;
cout << "性别:";
cin >> x.gender;
cout << endl;
cout << "住址:";
cin >> x.address;
cout << endl;
cout << "电话号码:";
cin >> x.phoneNumber;
cout << endl;
string line = "姓名:" + x.name + " 性别:" + x.gender + " 住址:" + x.address + " 电话号码:" + x.phoneNumber;//将联系人信息合并成一条string语句
cout << line << endl;//打印给用户检查
locale Oldlocale = locale::global(locale("zh_CN.UTF-8"));//改变编码方式为UTF-8,以防止乱码或输入后无法读取或输入进不去,并且记录原有环境为Oldlocale
wstring filePath = L"D:\\study C++\\通讯录系统\\联系人目录.txt";//记录路径
ofstream file(filePath, ios::app);//以写入流ofstream定义对象file并打开文件,ios::app表示以追加的方式打开文件
if (file.is_open())//判断文件是否打开
{
file << line << endl;//向其中添加联系人信息并且换行
file.close();//关闭文件
locale::global(Oldlocale);//将原有环境恢复防止菜单中的中文无法打印
cout << "已成功添加联系人!" << endl;
}
else cout << "无法打开文件!!!" << endl;
}
4.删除联系人:
对于文件的删除是将特定行以外的其余信息写入另一个文件最后进行替换:
void delete_people()
{
string targetName;
cout << "请输入您所要删除联系人的姓名:" << endl;
cin >> targetName;//记录需要删除的联系人姓名
wstring filePath = L"D:\\study C++\\通讯录系统\\联系人目录.txt";
fstream file(filePath, ios::in);//以只读的方式打开
if (file.is_open())
{
wstring tempFilePath = L"D:\\study C++\\通讯录系统\\temp.txt";//临时文件的路径
ofstream tempFile(tempFilePath);//创建一个临时文件
string line;
while (getline(file, line))
{ //当该行不包含姓名时,直接写入临时文件
size_t found = line.find(targetName);
if (found == string::npos)
{
tempFile << line << endl;
}
}
file.close();
tempFile.close();//关闭两个文件
cout << "已成功删除联系人" << targetName << endl;
const char* fileName = "D:\\study C++\\通讯录系统\\联系人目录.txt";
const char* tempFileName = "D:\\study C++\\通讯录系统\\temp.txt";
if (remove(fileName) != 0)
{
cout << "无法删除原始文件!" << endl;
return;
}
if (rename(tempFileName, fileName) != 0) // 将临时文件重命名为原始文件的名称
{
cout << "无法重命名临时文件!" << endl;
return;
}
}
else
{
cout << "无法打开文件!" << endl;
}
}
5.修改联系人:
修改与删除原理相似:
void modify_people()//修改联系人
{
string targetName;
cout << "请输入您所要修改联系人的姓名:" << endl;
cin >> targetName;
people x;
cout << "请按照提示输入联系人的相关信息" << endl;
cout << "姓名:";
cin >> x.name;
cout << endl;
cout << "性别:";
cin >> x.gender;
cout << endl;
cout << "住址:";
cin >> x.address;
cout << endl;
cout << "电话号码:";
cin >> x.phoneNumber;
cout << endl;
string xline = "姓名:" + x.name + " 性别:" + x.gender + " 住址:" + x.address + " 电话号码:" + x.phoneNumber;
cout << "修改后的信息为:" << xline << endl;
wstring filePath = L"D:\\study C++\\通讯录系统\\联系人目录.txt";
fstream file(filePath, ios::in);
if (file.is_open())
{
wstring tempFilePath = L"D:\\study C++\\通讯录系统\\temp.txt";
ofstream tempFile(tempFilePath);
string line;
while (getline(file, line))
{
size_t found = line.find(targetName);
if (found != string::npos)
{
tempFile << xline << endl;
}
else
{
tempFile << line << endl;//对特定行,进行新信息的输入
}
}
file.close();
tempFile.close();
const char* fileName = "D:\\study C++\\通讯录系统\\联系人目录.txt";
const char* tempFileName = "D:\\study C++\\通讯录系统\\temp.txt";
if (remove(fileName) != 0)
{
cout << "无法删除原始文件!" << endl;
return;
}
if (rename(tempFileName, fileName) != 0) // 将临时文件重命名为原始文件的名称
{
cout << "无法重命名临时文件!" << endl;
return;
}
}
else
{
cout << "无法打开文件!" << endl;
}
}
6.清空通讯录
以覆盖的形式打开文件,直接输入“”;
void clear_people()//清空通讯录
{
locale Oldlocale = locale::global(locale("zh_CN.UTF-8"));
wstring filePath = L"D:\\study C++\\通讯录系统\\联系人目录.txt";
ofstream file(filePath);
if (file.is_open())
{
file << "" << endl;
file.close();
locale::global(Oldlocale);
cout << "已成功清空联系人!" << endl;
}
else cout << "无法打开文件!!!" << endl;
}
最终代码
#include<iostream>
#include<fstream>
#include<locale>
#include<string>
using namespace std;
struct people
{
string name;
string gender;
string address;
string phoneNumber;
};
int show_menu();
void read_line();
void add_people();
void delete_people();
void modify_people();
void clear_people();
int main()
{
bool flag = true;
while (flag)
{
switch (show_menu())
{
case 1:
read_line();
break;
case 2:
add_people();
break;
case 3:
delete_people();
break;
case 4:
modify_people();
break;
case 5:
clear_people();
break;
case 0:
cout << "欢迎下次使用!!!" << endl;
flag = false;
break;
default:
cout << "您输入的数字不在范围之内!!!" << endl;
break;
}
}
return 0;
}
int show_menu()
{
cout << "~~~~~~~~~~~~~~~欢迎使用通讯录管理系统~~~~~~~~~~~~~~~" << endl;
cout << "\t1----显示所有联系人" << endl;
cout << "\t2----添加联系人" << endl;
cout << "\t3----删除联系人" << endl;
cout << "\t4----修改联系人" << endl;
cout << "\t5----清空联系人列表" << endl;
cout << "\t0----退出系统" << endl;
cout << "请您输入选项所对应的数字:" << endl;
int i = 0;
cin >> i;
return i;
}
void read_line()
{
wstring filePath = L"D:\\study C++\\通讯录系统\\联系人目录.txt";
ifstream file(filePath);
if (file.is_open())
{
string line;
while (getline(file, line))
{
cout << line << endl;
}
file.close();
}
else cout << "无法打开文件!!!" << endl;
}
void add_people()
{
people x;
cout << "请按照提示输入联系人的相关信息" << endl;
cout << "姓名:";
cin >> x.name;
cout << endl;
cout << "性别:";
cin >> x.gender;
cout << endl;
cout << "住址:";
cin >> x.address;
cout << endl;
cout << "电话号码:";
cin >> x.phoneNumber;
cout << endl;
string line = "姓名:" + x.name + " 性别:" + x.gender + " 住址:" + x.address + " 电话号码:" + x.phoneNumber;
cout << line << endl;
locale Oldlocale = locale::global(locale("zh_CN.UTF-8"));
wstring filePath = L"D:\\study C++\\通讯录系统\\联系人目录.txt";
ofstream file(filePath, ios::app);
if (file.is_open())
{
file << line << endl;
file.close();
locale::global(Oldlocale);
cout << "已成功添加联系人!" << endl;
}
else cout << "无法打开文件!!!" << endl;
}
void delete_people()
{
string targetName;
cout << "请输入您所要删除联系人的姓名:" << endl;
cin >> targetName;
wstring filePath = L"D:\\study C++\\通讯录系统\\联系人目录.txt";
fstream file(filePath, ios::in);
if (file.is_open())
{
wstring tempFilePath = L"D:\\study C++\\通讯录系统\\temp.txt";
ofstream tempFile(tempFilePath);
string line;
while (getline(file, line))
{
size_t found = line.find(targetName);
if (found == string::npos)
{
tempFile << line << endl;
}
}
file.close();
tempFile.close();
cout << "已成功删除联系人" << targetName << endl;
const char* fileName = "D:\\study C++\\通讯录系统\\联系人目录.txt";
const char* tempFileName = "D:\\study C++\\通讯录系统\\temp.txt";
if (remove(fileName) != 0)
{
cout << "无法删除原始文件!" << endl;
return;
}
if (rename(tempFileName, fileName) != 0)
{
cout << "无法重命名临时文件!" << endl;
return;
}
}
else
{
cout << "无法打开文件!" << endl;
}
}
void modify_people()
{
string targetName;
cout << "请输入您所要修改联系人的姓名:" << endl;
cin >> targetName;
people x;
cout << "请按照提示输入联系人的相关信息" << endl;
cout << "姓名:";
cin >> x.name;
cout << endl;
cout << "性别:";
cin >> x.gender;
cout << endl;
cout << "住址:";
cin >> x.address;
cout << endl;
cout << "电话号码:";
cin >> x.phoneNumber;
cout << endl;
string xline = "姓名:" + x.name + " 性别:" + x.gender + " 住址:" + x.address + " 电话号码:" + x.phoneNumber;
cout << "修改后的信息为:" << xline << endl;
wstring filePath = L"D:\\study C++\\通讯录系统\\联系人目录.txt";
fstream file(filePath, ios::in);
if (file.is_open())
{
wstring tempFilePath = L"D:\\study C++\\通讯录系统\\temp.txt";
ofstream tempFile(tempFilePath);
string line;
while (getline(file, line))
{
size_t found = line.find(targetName);
if (found != string::npos)
{
tempFile << xline << endl;
}
else
{
tempFile << line << endl;
}
}
file.close();
tempFile.close();
const char* fileName = "D:\\study C++\\通讯录系统\\联系人目录.txt";
const char* tempFileName = "D:\\study C++\\通讯录系统\\temp.txt";
if (remove(fileName) != 0)
{
cout << "无法删除原始文件!" << endl;
return;
}
if (rename(tempFileName, fileName) != 0)
{
cout << "无法重命名临时文件!" << endl;
return;
}
}
else
{
cout << "无法打开文件!" << endl;
}
}
void clear_people()
{
locale Oldlocale = locale::global(locale("zh_CN.UTF-8"));
wstring filePath = L"D:\\study C++\\通讯录系统\\联系人目录.txt";
ofstream file(filePath);
if (file.is_open())
{
file << "" << endl;
file.close();
locale::global(Oldlocale);
cout << "已成功清空联系人!" << endl;
}
else cout << "无法打开文件!!!" << endl;
}
fstream总结
fstream
是 C++ 标准库中用于文件输入输出的类。它是 iostream
类的派生类,提供了对文件的读写操作。
fstream
类定义了以下几个主要的成员函数:
open()
:用于打开文件。可以指定文件名以及打开模式,如读取模式、写入模式、追加模式等。close()
:用于关闭已打开的文件。is_open()
:用于检查文件是否成功打开。eof()
:用于检查是否到达文件末尾(End-Of-File)。fail()
:用于检查文件操作是否失败。good()
:用于检查流状态是否良好,即无错误发生。seekg()
和seekp()
:用于设置文件指针的位置,以便定位读写位置。tellg()
和tellp()
:用于获取当前文件指针的位置。getline()
:用于从文件中读取一行字符串。operator<<()
和 `operator>>():重载了插入运算符和提取运算符,用于向文件中写入数据和从文件中读取数据。
使用 fstream
进行文件操作的一般步骤如下:
- 创建
fstream
对象,指定文件名和打开模式。 - 使用
open()
函数打开文件。 - 判断文件是否成功打开,可以使用
is_open()
函数进行检查。 - 使用
operator<<()
或 `operator>>() 函数向文件写入数据或从文件读取数据。 - 使用
close()
函数关闭文件。
代码示例:
#include <fstream> #include <iostream> int main() { std::fstream file; file.open("data.txt", std::ios::out); // 打开文件用于写入模式 if (file.is_open()) { file << "Hello, World!" << std::endl; // 向文件写入数据 file.close(); // 关闭文件 } else { std::cout << "Failed to open the file." << std::endl; } file.open("data.txt", std::ios::in); // 打开文件用于读取模式 if (file.is_open()) { std::string line; std::getline(file, line); // 从文件读取一行数据 std::cout << "Data from file: " << line << std::endl; file.close(); // 关闭文件 } else { std::cout << "Failed to open the file." << std::endl; } return 0; }
locale总结
locale
是 C++ 标准库中的一个类,用于处理与本地化相关的操作。它提供了一种机制来处理语言、时间、货币等与地区有关的信息。locale
类定义了一种包含了特定地区相关信息的对象,可以在程序中使用这个对象来获取地域相关的数据和格式化输出。
locale
类的对象可以表示特定的地区,如 "zh_CN" 表示中国,"en_US" 表示美国等。通过设置合适的locale
对象,我们可以根据当前地区的习惯方式进行字符串的转换、时间日期的格式化、货币的显示以及其他与地区有关的操作。C++ 标准库提供了一些与
locale
相关的类和函数,例如std::locale
、std::numpunct
、std::money_get
、std::time_get
等。我们可以使用这些类和函数来实现与本地化相关的功能。在给定的代码示例中,
locale
用于设置程序的默认地区为 "zh_CN.UTF-8",以便正确处理中文字符的输入和输出。具体来说,在添加联系人和清空联系人列表时,程序会将locale
设置为 "zh_CN.UTF-8",以支持中文字符的写入和输出。设置之前会先保存原始的locale
,以便在操作完成后恢复为之前的地区设置。请注意,
locale
的使用需要依赖操作系统的支持,不同的操作系统可能有不同的地区编码和命名规则。因此,在实际使用中,建议根据具体的需求和目标地区选择合适的locale
设置。
locale
头文件中包含了一些重要的类和函数,用于处理与本地化相关的操作。下面是一些常用的 locale
类和函数的介绍:
-
std::locale
类:std::locale
是locale
库的核心类,表示一个特定的地区设置。它提供了许多函数和成员变量,允许我们查询和修改地区相关的设置。例如:std::locale()
:无参构造函数,创建一个默认的地区对象。std::locale(const char* name)
:使用给定的地区名称创建一个地区对象。std::locale::global(const std::locale& loc)
:将给定的地区对象设置为全局地区,在整个程序中生效。
-
std::numpunct
类:std::numpunct
是一个与数值格式化相关的类,用于控制数字的显示方式(如小数点、分组符号等)。我们可以通过继承std::numpunct
类并实现自定义的数字格式化规则来满足特定的需求。 -
std::money_get
和std::money_put
类:这两个类用于货币的输入和输出。std::money_get
类负责将字符串解析为货币值,而std::money_put
类负责将货币值格式化为字符串。 -
std::time_get
和std::time_put
类:这两个类用于时间和日期的输入和输出。std::time_get
类负责将字符串解析为时间值,而std::time_put
类负责将时间值格式化为字符串。 -
std::use_facet
函数:std::use_facet
是一个模板函数,用于获取特定类型的 facet(如std::numpunct
、std::money_get
、std::time_get
等)以进行定制化的操作。它可以根据当前的地区设置自动选择正确的 facet。