C语言用到最频繁的输入输出方式就是scanf ()与printf()。
scanf(): 从标准输入设备(键盘)读取数据,并将值存放在变量中。
printf(): 将指定的文字/字符串输出到标准输出设备(屏幕)。
注意宽度输出和精度输出控制
对输入输出缓冲区的理解
1.可以屏蔽掉低级I/O的实现,低级I/O的实现依赖操作系统本身内核的实现,如果能够屏蔽这部分的差异,可以很容易写出可移植的程序。
2.可以使用这部分的内容实现“行”读取的行为,计算机没有“行”这个概念,有了这部分,可以定义“行”的概念,解析缓冲区的内容,返回一个“行”。
C/C++IO的区别与联系
ostream/istream 支持自定义类型对象的流插入和流提取[重载]
int main()
{
//cin和scanf输入时 默认用空格/换行分割
int year = 0, month = 0, day = 0;
cin >> year >> month >> day;
//scanf("%d%d%d", &year, &month, &day);
//scanf("%d %d %d", &year, &month, &day); //也可以 没必要
cout << year << month << day;
//20231027
scanf("%4d%2d%2d", &year, &month, &day);
string str;
cin >> str;
year = stoi(str.substr(0, 4));
month = stoi(str.substr(4, 2));
day = stoi(str.substr(6, 2));
cout << year << month << day;
return 0;
}
“流”即是流动的意思,物质从一处向另一处流动的过程,是对一种有序连续且具有方向性的数据( 单位可以是bit,byte,packet)的抽象描述。
C++流是指信息从外部输入设备(如键盘)向计算机内部(如内存)输入和从内存向外部输出设备(显示器)输出的过程。
这种输入输出的过程被形象的比喻为“流”。特性:有序连续、具有方向性
牛客/力扣常见: 多个测试样例
int main()
{
int year, month, day;
string str;
while (cin >> str)
{
year = stoi(str.substr(0, 4));
month = stoi(str.substr(4, 2));
day = stoi(str.substr(6, 2));
cout << year << "年" << month << "月" << day << "日" << endl;
}
return 0;
}
为什么 cin >> str 能做为循环判断的条件?查阅文档如下
如果设置了故障位或坏位中的至少一个,则为空指针。其他一些值。
C++11 如果至少设置了其中一个错误标志(ctrl + Z +“+” 或者 ctrl + C[进程终止]),则函数返回false,否则返回true。
有些同学在这里看不懂operator bool是啥 建议看一下
重载强制类型转换运算符
class A
{
public:
/*不存在从"int" 转换到"A"的适当构造函数
explicit A(int _a)
:_a(_a)
{
}
*/
A(int _a)
:_a(_a)
{
}
//如果不重载int 报错: A类型无法转换成int
operator int()
{
return _a;
}
private:
int _a;
};
int main()
{
// 内置类型 转换成自定义类型
// 隐式类型转换
// 用1构造A类型的临时对象 拷贝构造给aa1
// 优化后1直接去构造aa1
A aa1 = 1; //若类A的构造函数加explicit 则隐式类型转换无法发生
//A& aa2 = 1; error
const A& aa2 = 1;//ok
A&& aa3 = 1;//ok
// 自定义类型 转换成内置类型
int i = aa1; //若类A的operator int()加上explicit 则无法转换
//但是强制类型转换依然行得通 或者static_cast
cout << i << endl;
return 0;
}
class Date
{
friend ostream& operator << (ostream& out, const Date& d);
friend istream& operator >> (istream& in, Date& d);
public:
Date(int year = 2023, int month = 10, int day = 27)
:_year(year)
, _month(month)
, _day(day)
{
}
explicit operator bool() const
{
//现在还没有2024年
if (_year == 2024)
return false;
else
return true;
}
private:
int _year;
int _month;
int _day;
};
istream& operator >> (istream& in, Date& d)
{
in >> d._year >> d._month >> d._day;
return in;
}
ostream& operator << (ostream& out, const Date& d)
{
out << d._year << " " << d._month << " " << d._day;
return out;
}
int main()
{
//cout 自动识别类型 -- 重载 流提取 运算符
/*
int b = 1;
double j = 2.2;
cout << b << endl;
cout << j << endl;
*/
Date d(2023, 10, 27);
cout << d << endl;
//d是Date类型的 Date类重载了bool
// 此处while循环判断的值是布尔类型
// 所以此处while(d) 相当于 while( d.operaotor bool() )
//while(cin >> str) ==> operator>>(cin, str)[istream类里重载了bool强制类型转换运算符]
while (d)
{
cin >> d;
if(d)
cout << "您输入的日期为: " << d << endl;
else
cout << "输入错误 循环终止!" << endl;
}
return 0;
}
C++标准库提供了4个全局流对象cin、cout、cerr、clog
使用cout进行标准输出,即数据从内存流向控制台(显示器)。
使用cin进行标准输入 , 即数据通过键盘输入到程序中,
cerr进行标准错误的输出
clog进行日志的输出
注意:
C++根据文件内容的数据格式分为二进制文件和文本文件
。采用文件流对象操作文件
的一般步骤:
文件流对象和磁盘文件
之间建立联系输出文件
int main()
{
ifstream ifs("test.cpp");
char ch = ifs.get();
while (ifs)
{
cout << ch;
ch = ifs.get();
}
return 0;
}
读文件
class Date
{
friend ostream& operator << (ostream& out, const Date& d);
friend istream& operator >> (istream& in, Date& d);
public:
Date(int year = 2023, int month = 10, int day = 27)
:_year(year)
, _month(month)
, _day(day)
{
}
private:
int _year;
int _month;
int _day;
};
istream& operator >> (istream& in, Date& d)
{
in >> d._year >> d._month >> d._day;
return in;
}
ostream& operator << (ostream& out, const Date& d)
{
out << d._year << " " << d._month << " " << d._day;
return out;
}
int main()
{
ifstream ifs("obj.txt");
int i;
string j;
double k;
Date d1;
Date d2;
Date d3;
ifs >> i >> j >> k >> d1 >> d2 >> d3;
cout << i << endl << j << endl << k << endl << d1 << endl << d2 << endl << d3 << endl;
return 0;
}
class Date
{
friend ostream& operator << (ostream& out, const Date& d);
friend istream& operator >> (istream& in, Date& d);
public:
Date(int year = 2023, int month = 10, int day = 27)
:_year(year)
, _month(month)
, _day(day)
{
}
operator bool()
{
if (_year == 0)
return false;
else
return true;
}
private:
int _year;
int _month;
int _day;
};
istream& operator >> (istream& in, Date& d)
{
in >> d._year >> d._month >> d._day;
return in;
}
ostream& operator << (ostream& out, const Date& d)
{
out << d._year << " " << d._month << " " << d._day;
return out;
}
//ifstream
/*
int main()
{
ifstream ifs("obj.txt");
int i;
string j;
double k;
Date d1;
Date d2;
Date d3;
ifs >> i >> j >> k >> d1 >> d2 >> d3;
cout << i << endl << j << endl << k << endl << d1 << endl << d2 << endl << d3 << endl;
return 0;
}
*/
// 二进制读写:数字在内存以补码存储 则以补码写到磁盘文件
// 优点:速度快
// 缺点:内容不可视(乱码)
// 文本读写:对象-序列化->字符串写至文件 读出的也是字符串-反序列化->对象
// 优点:内容可视(字符串形式)
// 缺点:存在转换过程 速度相比较慢
struct ServerInfo
{
string _address;
// 二进制读写VS下
//当字符串短 能读出来但报错
//当字符长无法读出来: vs的string短的存入缓存数组 长的存至堆
// 写文件时实际上是把指向堆空间的指针写至文件
// 读文件时 无法访问到堆空间的数据
//Linux下短的长的都读不到
//文本读写利用c_str访问指针指向的空间
//char _address[32];
int _port;
Date _date;
};
//配置管理器
struct ConfigManager
{
public:
//构造函数
ConfigManager(const char* filename = "server.config")
:_filename(filename)
{
}
/
//二进制写cout
void WriteBin(const ServerInfo& info)
{
ofstream ofs(_filename, ios_base::out | ios_base::binary);
ofs.write((char*)&info, sizeof(info));
}
//二进制读
void ReadBin(ServerInfo& info)
{
ifstream ifs(_filename, ios_base::in | ios_base::binary);
ifs.read((char*)&info, sizeof(info));
}
/
//文本写
void WriteText0(const ServerInfo& info)
{
ofstream ofs(_filename, ios_base::out);
ofs.write(info._address.c_str(), info._address.size());
ofs.put('\n');
const string str = to_string(info._port);
ofs.write(str.c_str(), str.size());
}
void WriteText(const ServerInfo& info)
{
ofstream ofs(_filename, ios_base::out);
ofs << info._address << endl;
ofs << info._port << endl;
ofs << info._date << endl;
}
//文本读
void ReadText0(ServerInfo& info)
{
ifstream ifs(_filename, ios_base::in);
char buff[128];
ifs.getline(buff, 128);
info._address = buff;
ifs.getline(buff, 128);
info._port = stoi(buff);
}
void ReadText(ServerInfo& info)
{
ifstream ifs(_filename, ios_base::in);
ifs >> info._address >> info._port >> info._date;
}
private:
string _filename; // 配置文件
};
//二进制读写
//int main()
//{
// ServerInfo winfo = { "123CSDN阿猿", 123 };
//
// // 二进制写
// ConfigManager cm;
// cm.WriteBin(winfo);
//
// // 二进制读
// ServerInfo rinfo;
// cm.ReadBin(rinfo);
//
// //输出
// cout << rinfo._address << endl;
// cout << rinfo._port << endl;
//
// return 0;
//}
int main()
{
ConfigManager cm;
// 文本写
ServerInfo winfo = { "547CSDN阿猿", 547, {2023, 10, 29 } };
cm.WriteText(winfo);
// 文本读
ServerInfo rinfo;
cm.ReadText(rinfo);
cout << rinfo._address << endl;
cout << rinfo._port << endl;
cout << rinfo._date << endl;
return 0;
}
C语言将一个整形的数据转化为字符串格式
两个函数在转化时
使用stringstream,必须要包含头文件#include
。
在该头文件下,标准库三个类:istringstream、ostringstream 和 stringstream
分别用来进行流的输入、输出和输入输出操作
stringstream主要作用
#include
int main()
{
int a = 12345678;
stringstream ss;
string str;
ss << a;
ss >> str;
string sValue;
sValue = ss.str();
cout << sValue << endl;
// clear()
// 多次转换 必须使用clear将上次转换状态清空掉
// stringstreams在转换结尾时(即最后一个转换后),会将其内部状态设置为badbit
// 下一次转换必须调用clear()将状态重置为goodbit才可以转换
// !!!clear()不会将stringstreams底层字符串清空掉!!!
// ss.str("");
// 将stringstream底层字符串清空
// 否则多次转换时,会将结果全部累积在底层string对象中
ss.str("");
ss.clear();
double d = 12.34;
ss << d;
ss >> str;
sValue = ss.str();
cout << sValue << endl;
return 0;
}
int main()
{
stringstream ss;
ss << "first" << " " << "string,";
ss << " second string";
cout << "strResult is: " << ss.str() << endl;
ss.str("");
ss << "third string";
cout << "After clear, strResult is: " << ss.str() << endl;
return 0;
}
struct ChatInfo
{
string _name; // 名字
int _id; // id
Date _date; // 时间
string _msg; // 聊天信息
};
int main()
{
// 序列化
ChatInfo winfo = { "WZD", 547993, { 2023, 10, 29 }, "假期一起旅行吧!" };
//ostringstream oss;
stringstream oss;
//把数据序列化成字符串写至oss
oss << winfo._name << endl;
oss << winfo._id << endl;
oss << winfo._date << endl;
oss << winfo._msg << endl;
string str = oss.str();
cout << str << endl;
// 网络传输str,另一端接收到了字符串串信息数据
// 反序列化
ChatInfo rInfo;
//istringstream iss(str);
stringstream iss(str);
//将字符串传参给iss 将iss中的字符串反序列化成对象给成员属性
iss >> rInfo._name;
iss >> rInfo._id;
iss >> rInfo._date;
iss >> rInfo._msg;
cout << "----------------------------------" << endl;
cout << rInfo._date << endl;
cout << rInfo._name << "[" << rInfo._id << "]:>" << rInfo._msg << endl;
cout << "----------------------------------" << endl;
return 0;
}