(一)输入输出
- 程序的输入:从输入文件将数据传送给程序
- 程序的输出:从程序将数据传送给输出文件
C++的输入主要包括:对系统指定标准设备的输入输出(如从键盘输入,从显示器输出);以外存(磁盘、光盘等)为对象进行输入输出;对内存中指定空间进行输入输出。
(二)输入输出流
输入和输出是数据传输的过程被称为流。流表示了信息从源到目的端的流动,有序连续,具有方向性。
实际上,在内存中为每个数据流开辟一个内存缓冲区,用来存放流中的数据,即缓冲区中的数据就是流。
C++中,输入输出流被定义为类;I/O库中的类称为流类;用流类定义的对象称为流对象。
(三)IO类
不同种类的IO处理操作主要定义在三个独立的头文件中:iostream定义了用于读写流的基本类型,fstream定义了读写命名文件的类型,sstream定义了读写内存string对象的类型。
头文件 类型
iostream istream,wistream从流读取数据
ostream,wostream从流写入数据
iostream,wiostream读写流
fstream ifstream,wifstream从文件读取数据
ofstream,wofstream向文件写入数据
fstream,wfstream读写文件
sstream istringstream,wistringstream从string读取数据
ostringstream,wostringstream向string写入数据
stringstream,wstringstream读写string
为了支持使用宽字符的,标准库定义了一组类型和对象来操纵wchar_t类型的数据,宽字符版本的类型和函数的名字以一个w开始。
(1)C++标准IO流
对象 | 含义 | 对应设备 | 有无缓冲区 |
cin | 标准输入流 | 键盘 | 有缓冲区 |
cout | 标准输出流 | 键盘 | 有缓冲区 |
cerr | 标准错误流 | 屏幕 | 无缓冲区 |
clog | 标准错误流 | 屏幕 | 有缓冲区 |
- cin为缓冲流,键盘输入的数据保存在缓冲区,当需要提取时,从缓冲区提取;遇到Enter键完成输入;
-
//敲回车键的有 int a; cin >> a; char c; c = getchar(); int b; scanf("%d", &b); //末尾会添加一个空字符,如果键入1234567890会中断 //只能键入123456789 char str[10]; gets(str, 10);
- 输入数据类型和要提取数据类型一致
- cin和cout可以直接输入和输出内置类型数据
- 对于自定义的类型,如果要支持cin和cout的标准输入输出,需要对<<和>>进行重载
(2)IO对象无拷贝或赋值
由于不能拷贝IO对象,因此我们不能将形参活返回类型设置为流类型,进行IO操作的函数通常以引用方式传递和返回流,读写一个IO对象会改变其状态,因此其引用不能是const的。
ofstream out1, out2;
out1 = out2; //错误,不能对流对象赋值
ofstream print(ofstream); //错误,不能初始化ofstream参数
out2 = print(out2); //错误,不能拷贝流对象
(3)条件状态
IO操作一个与生俱来的问题就是可能发生错误,一些错误是可恢复的,而一些错误是发生在系统深处,已经超出应用程序可以修正的范围,而IO类所定义的一些函数和标志,可以帮助我们访问和操纵流的条件状态。
下面是一个错误的例子:
int val;
cin >> val;
如果我们在标准输入上键入Boo,该操作就会失败,因为代码中输入运算符期待读取一个int,但却得到了一个字符B。
一旦一个流发生了错误,其上后续的IO操作都会失败,只有当一个流处于无错误状态,我们才可以从它读取数据。确定一个流对象的状态最简单的方法就是将它当作一个流来使用:
while(cin >> word)
//ok:读操作成功......
(四)C++文件IO流
暂补充
(五)C++ stringstream
- 将整型变量的数据转换为字符串格式:(1)使用itoa()函数(2)使用sprintf()函数,但是使用时都得需要先给出保存结果的空间,而且转换格式需要匹配
int n = 123456789;
char s1[32];
_itoa(n, s1, 10);
cout << s1 << endl; //123456789
char s2[32];
sprintf(s2, "%d", n);
cout << s2 << endl; //123456789
char s3[32];
sprintf(s3, "%f", n);
cout << s3 << endl; //0.000000
char s4[32];
float n1 = 3.2;
sprintf(s4, "%f", n1);
cout << s4 << endl; //3.200000
- 在C++中,可以使用stringstream类对象避开此问题,避免缓冲区溢出的危险,而且会对参数类型进行推演,不需要格式化控制,使用更安全。stringstream实际时在其底层维护了一个string类型的对象来保存结果
- 多次数据类型转换时,一定要用clear(),才能正确转换,但clear()不会将stringstream底层的string对象清空
int a = 123456;
stringstream ss; //字符串读写流
string str;
ss << a; //a->ss
ss >> str; //ss->str
cout << str << endl; //输出123456
ss.clear(); //清空ss
float f = 1.2;
ss << f;
ss >> str;
cout << str << endl; //输出1.2
- stringstream可以完成字符串拼接,可以使用s.str("")方法将底层string对象设置为""空字符串,可以使用s.str()让stringstream返回其底层的string对象
stringstream ss;
//把多个字符串放入stringstream
ss << "first" << " " << "string,";
ss << " second string";
cout << ss.str() << endl; //输出first string, second string
//clear() 操作,并不会清除底层string对象
ss.clear();
cout << ss.str() << endl; //输出first string, second string
//删除底层,使用s.str("");
ss.str("");
ss << "third string";
cout << ss.str() << endl; //输出third string
补充一下:
(六)string 与 char* 和char[]的相互转换
(1)string 转换为 char*和char[]
- 使用data()方法
string str = "fisrt str";
const char* p1 = str.data();
cout << p1 << endl; //输出fisrt str
- 使用c_str()方法
string str = "fisrt str";
const char* p1 = str.c_str();
cout << p1 << endl; //输出fisrt str
- 使用copy()方法
string str = "fisrt str";
int len = str.length();
char* p = new char[len + 1];
str.copy(p, len, 0); //第二个参数表示复制几个字符,第三个参数表示赋值的起始位置
*(p + len) = '\0'; //一定要加上
cout << p << endl; //输出fisrt str
(2)char[] 转换为string
多种方法,这里记录两种
- 向构造函数传入c字符串创建string对象
- 使用拷贝构造函数创建string对象
char c[] = "hello world";
//构造函数
string str(c);
//拷贝构造函数
string str = c;
(七)string 转换为整数
string k = "12345";
cout << atoi(k.data()) << endl;
cout << atoi(k.c_str()) << endl;