输入输出流

本文详细介绍了C++中的输入输出流,包括用途、库文件、流类、控制符、标准输入输出流的控制、格式设置、为什么使用流、运算符重载以及与C语言的对比。C++的iostream库提供了cin、cout、cerr和clog等流对象,支持与键盘、控制台和文件的交互,并允许通过操纵符设置输出格式。此外,还讨论了如何自定义输入输出操作以适应自定义类。
摘要由CSDN通过智能技术生成

输入输出流

1 输入输出流的用途

C++ prévoit des entrées / sorties à l’aide d’objets (appelés flots), vers trois média différents:
C++ 使用对象(称为流)提供输入/输出,到三种不同的媒体:

  1. la console / le clavier (standard) : cin, cout → déclarations dans <iostream>
  2. les fichiers → déclarations dans <fstream>
  3. la mémoire (buffers: tableau de char ou string) → déclarations dans <strstream> et <sstream>

2 库文件与流类

Ils font partie de la Standard Template Library:
它们是标准模板库的一部分
inclusion et accès direct :

#include<iostream>//控制台
using namespace std;
void main(){ cout<<"Coucou !\n"; }

inclusion et accès indirect :

#include<iostream>//控制台
void main(){ std::cout<<"Coucou !\n"; }

cin 和 cout 的定义是在 iostream 中,命名空间为 std。
<< 是流插入运算符;>> 是流提取运算符;如果你要输出,那么肯定是要把字符串或者变量什么的传递给 cout 所以箭头要指向 cout,如果你要进行输入,那么就要从 cin 提取内容赋值给变量:例如:int x = 0;cin >> x;
不管是 cin 也好,cout 也好,<< 和 >> 一次性只能输出或者输入一个
一般 C++ 中的 cin 和 cout 是适用于我们当前使用的控制台类型的工程,这样才能看到输入与输出的结果。以后大家接触到带界面的程序了,cin 和 cout 也就用不上了。

3 流类

Architecture de classes et templates des streams STL
STL 流的类和模板的体系结构

在这里插入图片描述

4 流类

Les trois familles partagent la base virtuelle unique appelée basic_ios
这三个家族共享一个名为 basic_ios 的基类

4x2 flots standard dans <iostream>: 4x2 标准流:
cin, wcin pour les entrées du clavier 键盘输入:
instances globale de istream et wistream
cout, wcout pour les sorties vers la console控制台输出:
instance globale de ostream et wostream
cerr, wcerr pour les messages d’erreur错误消息 (défaut: console)(控制台):
instance globale de ostream et wostream
clog, wclog pour les messages d’activité活动消息 (défaut: console)(控制台):
instance globale de ostream et wostream

C++标准库提供了4个全局流对象cin、cout、cerr、clog。使用cout进行标准输出,即数据从内存流向控制台(显示器);使用cin进行标准输入,即数据通过键盘输入到程序中;使用cerr用来进行标准错误的输出;使用clog进行日志的输出。
从前图可以看出,cout、cerr、clog是ostream类的三个不同的对象,因此这三个对象基本没有区别,只是应用场景不同。
如下图所示都是向显示器输出,本意是希望一般的输出用cout,错误输出用cerr,日志输出用clog,但一般很少用到后两个,全部用cout输出。在这里插入图片描述
cin、cout与scanf、printf:
C++提供了cin、cout,C语言提供了scanf、printf,他们都可以进行输入输出,但建议能用cin、cout就优先用这两个,如果遇到格式化输入输出时用scanf、printf(cin、cout同样可以格式化输入输出,但是使用起来比较复杂,不如直接用现成的scanf、printf)。
同时,由于C++在某些方面与C语言有较大差异,有时混用四个输入输出也会出现问题。比如字符串string在C++中用size值来标记字符串的结尾,而C语言下用’\0’来标示字符串的结尾,这一个差异在输入输出时就可能会产生问题,为此string还特意提供了c_str()来用于C语言下的操作。

5 控制符

Les opérateurs << et >> sont surchargés pour tous les types natifs (char, short, int, long etc.)
运算符 << 和 >> 对于所有本机类型(char、short、int、long 等)都被重载

istream& istream::operator>>(type_de_base& variable) {/* ... */}
ostream& ostream::operator<<(const type_de_base& variable) {/* ... */}

Manipulateurs : 控制符:
– ils s’insèrent comme les variables et modifient le comportement des flux (temporairement ou non)
– pour les manipulateurs avec paramètre il faut inclure
– 它们像变量一样插入并修改流的行为(临时变量或没有)
– 对于带有参数的控制符包括

cin和cout可以直接输入和输出内置类型(如int、double等)和部分标准自定义类型(如string等),原因是标准库已经将所有这些类型的输入和输出重载了,直接使用即可。
在这里插入图片描述

6 标准输入输出流的控制符

Persistance 持续性
在这里插入图片描述

io代表输入输出,manip是manipulator(操纵器)的缩写(在c++上只能通过输入缩写才有效。)
主要是对cin,cout之类的一些操纵运算子,比如setfill,setw,setbase,setprecision等等。它是I/O流控制头文件,就像C里面的格式化输出一样。
dec 设置整数的基数为10
hex 设置整数的基数为16
oct 设置整数的基数为8
setbase(n) 设置整数的基数为n(n只能是16,10,8之一)
setfill© 设置填充字符c,c可以是字符常量或字符变量
setprecision(n) 设置实数的精度为n位。在以一般十进制小数形式输出时,n代表有效数字。在以fixed(固定小数位数)形式和scientific(指数)形式输出时,n为小数位数。
setw(n) 设置字段宽度为n位。
setw(int n); 预设输出宽度
setfill(Char c); 使用c作为填充字符
setbase(int n); 预设整数输出进制
setprecision(int n) 用于控制输出流浮点数的精度,整数n代表显示的浮点数数字的精度(四舍五入)。

#include <iostream>   // 标准输入输出流
#include <iomanip>    // 格式控制
using namespace std;
int main()
{
    double n;    
    cin >> n;
    // 假设输入:123.45    
    cout << n << endl;
    // 输出: 123.45     
    cout << setprecision(1) << n <<endl     // 控制精度为1,四舍五入后输出 123.5
         << setprecision(2) << n <<endl;   // 控制精度为2,四舍五入后输出 123.45    
    cout << setfill('*') << setw(7) << n << endl;  // 位宽为7,由于n只有6位,所以左边补充一个*,输出    *123.45    
    return 0;
}

7 设置格式状态的格式标志

在这里插入图片描述

setiosflags(ios::fixed) 设置浮点数以固定的小数位数显示
setiosflags(ios::scientific) 设置浮点数以科学计数法表示
setiosflags(ios::left) 输出左对齐 setiosflags(ios::right) 输出右对齐
setiosflags(ios::showpos) 输出正数时显示"+"号
setiosflags(ios::showpoint) 强制显示小数点
resetiosflags() 终止已经设置的输出格式状态,在括号中应指定内容

ios::left 输出数据在本域宽范围内左对齐
ios::right 输出数据在本域宽范围内右对齐
ios::internal 数值的符号位在域宽内左对齐,数值右对齐,中间由填充字符填充
ios::dec 设置整数的基数为10
ios::oct 设置整数的基数为8
ios::hex 设置整数的基数为16
ios::showbase 强制输出整数的基数(八进制以0打头,十六进制以0x打头)
ios::showpoint 强制输出浮点数的小点和尾数0
ios::uppercase 在以科学计数法输出E和十六进制输出字母X时,以大写表示
ios::showpos 输出正数时,给出“+”号。
ios::scientific 设置浮点数以科学计数法(即指数形式)显示
ios::fixed 设置浮点数以固定的小数位数显示
ios::unitbuf 每次输出后刷新所有流
ios::stdio 每次输出后清除 stdout,stderr

#include <iostream>
using namespace std;
int main()
{
   int a=21;
   cout.setf(ios::showbase); //设置输出时的基数符号
   cout<<"dec:"<<a<<endl; //默认以十进制形式输出a
   cout.unsetf(ios::dec); //终止十进制的格式设置
   cout.setf(ios::hex); //设置以十六进制输出的状态
   cout<<"hex:"<<a<<endl; //以十六进制形式输出a
   cout.unsetf(ios::hex); //终止十六进制的格式设置
   cout.setf(ios::oct); //设置以八进制输出的状态
   cout<<"oct:"<<a<<endl; //以八进制形式输出a
   cout.unsetf(ios::oct); //终止以八进制的输出格式设置
   char *pt="China"; //pt指向字符串”china”
   cout.width(10); //指定域宽为10
   cout<<pt<<endl; //输出字符串
   cout.width(10); //指定域宽为10
   cout.fill('*'); //指定空白处以'*'填充
   cout<<pt<<endl; //输出字符串
   double pi=22.0/7.0; //计算pi值
   cout.setf(ios::scientific);//指定用科学记数法输出
   cout<<"pi="; //输出"pi="
   cout.width(14); //指定域宽为14
   cout<<pi<<endl; //输出"pi值
   cout.unsetf(ios::scientific); //终止科学记数法状态
   cout.setf(ios::fixed); //指定用定点形式输出
   cout.width(12); //指定域宽为12
   cout.setf(ios::showpos); //在输出正数时显示“+”号
   cout.setf(ios::internal); //数符出现在左侧
   cout.precision(6); //保留6位小数
   cout<<pi<<endl; //输出pi,注意数符“+”的位置
   return 0;
}

8 为什么使用输入输出流

Pourquoi les flots d’E/S ?为什么使用输入输出流?
Plus sûr vis-à-vis des fautes de codage :更安全地防止编码错误:

void main(){
int i1, i2;
double d1;
// double erreur à l'exécution !!!
scanf("%d%d%lf", &i1, &d1, i2);
// appel automatique du bon opérateur
cin >> i1 >> d1 >> i2;
}

(Presque) indispensables dans les templates
Il ne faut jamais mélanger les fonctions de stdio.h avec les flots de iostream
不要混合使用

9 输入输出运算符重载

Extension à n’importe quel objet (surcharge par fonction car opérande droit) :
扩展到任何对象(因为右操作数而被函数重载):

class CCercle{
   float x, y, r;
   friend ostream& operator<<(ostream& os, const CCercle& c);
};
  ostream& operator<<(ostream& os, const CCercle& c){
  return os<<"Cercle de rayon "<<c.r<<" et centre (" << c.x <<","<< c.y <<")\n";
}

10

Si l’on veut éviter la déclaration d’amitié, écrire puis utiliser une méthode dédiée :
如果您想避免声明友谊,请使用专用方法编写:

class CCercle
{
float x, y, r;
public:
ostream& Affiche(ostream& os) const{
return os<<"Cercle de rayon "<< r<<" et centre (" << x <<","<< y <<")\n";}
};
ostream& operator<<(ostream& os, const CCercle& c){ return c.Affiche(os); }

11 输入输出流用法

Utilisation des flots C++vers des fichiers使用 C++ 流到文件
Les flots “fichiers” fstream sont directement compatibles avec les ostream et istream. Il faut juste créer un objet de type fstream.
fstream“文件”流直接与 ostream 和 istream 兼容。 您只需要创建一个 fstream 类型的对象。
在这里插入图片描述

1.定义一个文件流对象:ifstream(只输入用)、ofstream(只输出用)、fstream(既输入又输出用)
2.使用文件流对象的成员函数打开一个磁盘文件,使得文件流对象磁盘文件之间建立联系
3.使用提取和插入运算符对文件进行读写操作,或使用成员函数进行读写
4.关闭文件
关于模式:在这里插入图片描述

12 输入输出到文件

Il n’y a pas de différence à l’utilisation entre cout et un fichier,stream ouvert en mode “sortie” :
cout和文件在用法上没有区别,在“输出”模式下打开流:

#include<iostream>      //
#include<fstream>      //三个标准库
using namespace std;   //
   void main(){
     CCercle c(1.0f, 3.0f, 4.0f);
     cout << c;
     fstream fs("cercle.txt",ios::out);//输入输出,ios::out只写
     ofstream fs2("cercle2.txt");//只输出用(只写)
     fs << c;
     if(fs2) fs2 << c; // ou if(!fs2.fail()) ...
     else cout<<"Impossible d'ouvrir \"cercle.txt\"\n";
}

ifstream对象可调用的成员函数,常用的有get,getline,read,seekg,tellg等。通过函数名即可大致了解其作用。get一次获取文件的一个字符,getline一次获取文件的一行,read从文件中读一段内容,seekg设置文件指针的位置,tellg查找文件指针的位置。
下面模仿C中的写法。:在这里插入图片描述> 在这里插入图片描述

13 输入输出字符串

Il n’y a pas de différence à l’utilisation entre cout et un ostringstream vers un objet de type string :
对于字符串类型的对象,cout 和 ostringstream 之间没有使用区别:

#include<iostream>
#include<sstream>
using namespace std;
void main(){
     CCercle c(1.0f, 3.0f, 4.0f);
     cout << c;
     ostringstream os; // flux de sortie basé sur string
     os << c; // on affiche dans le string
     cout << os.str(); // on affiche la copie du string
}

sstream中包括istringstream、ostringstream 和stringstream三个流,分别用来进行流的输入、输出和输入输出操作,但使用时一般直接用stringstream比较方便。
在这里插入图片描述
在这里插入图片描述

14 输入输出字符数组

Il n’y a pas de différence à l’utilisation entre cout et un ostrstreamvers un tableau de caractères :
cout 和 ostrstream 对字符数组的用法没有区别:

#include<iostream>
#include<strstream>
using namespace std;
void main(){
   CCercle c(1.0f, 3.0f, 4.0f);
   cout << c;
   const size_t BUF_SZ=1024; // attention à la taille !
   char buf[BUF_SZ]; // notre buffer externe
   ostrstream os(buf, BUF_SZ); // flux basé surbuf[]
   os << c << ends; // le tableau n'a pas de '\0' !!!
   cout << buf;
}

os << c << ends; // le tableau n’a pas de ‘\0’ !!!
注意这一点:
endl等价于换行加刷新输出缓冲区。
ends等价于输出一个’\0’(空白字符)。
flush只有刷新输出缓冲区的功能,主要用在IO中,即清空缓冲区数据,一般在读写流(stream)的时候,数据是先被读到了内存中,再把数据写到文件中,当你数据读完的时候不代表你的数据已经写完了,因为还有一部分有可能会留在内存这个缓冲区中。这时候如果调用close()方法关闭了读写流,那么这部分数据就会丢失,所以应该在关闭读写流之前先flush()。

15

Une autre version sans utilisation de tableau (buffer) externe de char, il est géré en interne
另一个不使用外部字符数组(缓冲区)的版本,它是在内部处理的

CCercle c1(1.0f, 3.0f, 4.0f), c2(2, 2, 4);
cout << c1 << c2;
ostrstream os; // gestion interne de buffer
os << c1 << c2; // le buffer n'a pas de '\0' !!!
os << ends; // on rajoute '\0' à la fin
cout << os.str();// on affiche tout le buffer de char

16 与C语言对比

Tableau d’équivalences 等价表
在这里插入图片描述

有关C语言:

>  printf(格式化字符串,参数列表);`  
>  scanf(格式化字符串,&参数列表);`
>  //格式化字符串:表示整数型%d 表示字符型%c 表示浮点型%lf 表示字符串%s
>  FILE *fp;     //定义一个指向文件的指针变量
>  fp = fopen("her","r")//将fopen的返回值赋给指针变量fp
>  fclose(文件指针)>  fprintf(fp,"%s",a)//把a的值写入fp文件指向的位置中。
>  scanf(fp,"%s",a)//把文件fp指向的位置的值赋给a。
>  fputc(字符c,文件指针fp)//把字符c写入到指针变量fp所指的文件中
>  fputs(字符串str,文件指针fp)//把字符串写入到fp所指向的文件中
>  fgetc(文件指针);                      //从fp指向的文件中读取一个字符 
>  fgets(数组str,长度n,文件指针fp);        //从fp指向的文件读取长度为(n-1)的字符存入数组str中并在最后加一个字符 '\0'; ```

`

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值