首页 > 其他分享 >12.流输入输出

12.流输入输出

时间:2024-08-31 13:36:27浏览次数:3  
标签:字符 12 cout int 输入输出 cin char include

12. 流输入输出

12.1 Introduction

在C++ 程序中,首选C++样式的 I/O 而不是C样式的 I/O。


12.2 流(Streams)

C++ I/O occurs in streams, which are sequences of bytes. C++ provides both “low-level” and “high-level” I/O capabilities. Low-level I/O capabilities (i.e., unformatted I/O) specify that some number of bytes should be transferred device-to-memory or memory-to-device. In such transfers, the individual byte is the item of interest. Such low-level capabilities provide high-speed, high-volume transfers but are not particularly convenient. Programmers generally prefer a higher-level view of I/O (i.e., formatted I/O), in which bytes are grouped into meaningful units, such as integers, floating-point numbers, characters, strings and user-defined types. These type-oriented capabilities are satisfactory for most I/O other than high-volume file processing.


12.2.1 Classic Streams vs. Standard Streams

以前,C++经典流库(classic stream libraries)只支持char类型基础的I/O操作。因为char类型只占用一个字节,它只能表示有限的一组字符(例如ASCII码)。然而许多语言使用的字母表中包含的字符数量多于单个字节char所能表示的数量。The ASCII character set does not provide these characters, but the Unicode® character set does.Unicode is an extensive international character set that represents the majority of the world’s languages, mathematical symbols and much more. C++ provides Unicode support via the types wchar_t (the original C++ type for processing Unicode) and C++11 types char16_t and char32_t.

此外,标准流库(standard stream libraries)被实现为类模板式的类数组和向量。

12.2.2 iostream Library Headers

The<iostream> header defines the cin, cout, cerr and clog objects, which correspond to the standard input stream, the standard output stream, the unbuffered standard error stream and the buffered standard error stream, respectively.The <iomanip> header declares the parameterized stream manipulators such as setprecision and setw —for formatted I/O.

12.2.3 Stream Input/Output Classes and Objects

The iostream library defines each alias with the typedef specifier, which you'll sometimes use to create more readable type names. For example, the following statement defines the alias CardPtr as a synonym for type Card*:

typedef Card* CardPtr;

12.3 流输出(Stream Output)

cout与cin本质上是对象。

格式化和非格式化的输出能力由ostream提供。Capabilities include output of standard data types with the stream insertion operator (<<); output of characters via the put member function; unformatted output via the write member function; output of integers in decimal, octal and hexadecimal formats; output of floatingpoint values with various precision, with forced decimal points, in scientific notation (e.g., 1.234567e-03) and in fixed notation (e.g., 0.00123457); output of data justified in fields of designated widths; output of data in fields padded with specified characters; and output of uppercase letters in scientific notation and hexadecimal notation.

C++中最重要的三个输出流:ostream\ofstream\ostringstream 还有三个预定义好的输出流对象:cout\cerr\clog


12.3.1. Output of char* Variables

#include <iostream>
using namespace std;

int main() {
    const char* const word{"again"};

    cout<<"Value of word is: "<<word
       <<"\nValue of static_cast<const void*>(word) is:"
       <<static_cast<const void*>(word)<<endl;
}

在上述代码中,char类型的指针指向字符串again的首字符地址。

在 C++ 程序中,字符串可以存储在字符数组中,我们可以用指针访问数组,自然也就可以用指针访问字符串。

字符串指针本质是一个 char 类型的指针,然后将它指向一个字符串的开头,即字符串中的第一个字符。

12.3.2 C风格字符串

字符串指针

用指针指向字符串,和指向数组没有什么区别,要么在定义指针后给指针赋值,要么在定义时就初始化。

例如:

char str[] = "http://c.biancheng.net";
char* p = str;//初始化字符指针,令其指向 str 数组中的字符串

char* q; // 定义一个字符指针
q = str; // 令其指向字符串的开头

实际场景中,我们还会经常见到如下定义的字符串指针:

char *p = "http://c.biancheng.net";

字符串“Hello World!”存放在内存中的常量区,指针 p 指向常量区中的这个字符串。

注意,常量区的内容是不允许修改的,因此对于上面定义的字符串 "http://c.biancheng.net",不可以通过指针 p 修改它。

字符指针指向字符串的方法:

由于字符串在内存中连续存储的特点,可以使用指针进行操作,并且指针必须是字符型的。通常将指针指向字符串的首地址,利用指针的后移可以指向后续字符。字符指针指向字符串一般有三种的方法:

1.为字符指针初始化字符串首地址

例如:char *p = "I am happy";
这时字符串常量 "I am happy" 在内存中占用11个字节,以上初始化过程是将这段存储空间的首地址赋给字符型指针p,我们称指针p指向字符串"I am happy",存储示意图如下所示:

字符串指针变量的定义说明与指向字符变量的指针变量说明只能按对指针变量的赋值不同来区别。
例如:
char c,*p=&c;
表示p是一个指向字符变量c的指针变量。
而:
char *s="C Language";
则表示s是一个指向字符串的指针变量。把字符串的首地址赋予s。
2.为字符指针赋值字符串首地址

例如:

char *p;
p = "I am happy";

以上赋值语句“p = "I am happy";”是将字符串存储空间的首地址赋给指针p,然后p便指向字符串。注意不是将字符串赋给指针p。

3.让指针指向存放字符串的数组

char a[20] = "I am happy", *p = a;

以上定义了字符数组a并为之初始化字符串"I am happy",然后定义了字符指针p,将p初始化为指向数组a的首地址,即指向了字符串的第一个字符 'I'。

一般来说,如果给cout提供一个指针,它将打印地址。但如果指针的类型为char*,cout将显示指向的字符串。如果要显示字符串的地址,则必须将这种指针强制转换成另一种指针类型。例如:

char ch = 'A';
cout << &ch;  // A

对于上述代码,从类型的角度而言,&ch​的类型为char*​,而字符串的类型为const char*​,字符数组退化后的类型为char*​,因此类型的角度而言无法区分它指的是字符串的地址还是字符的地址,统一按字符串处理。

字符串的类型实际上是由常量字符构成的数组(array)。而字符数组的类型为const char* ,所以字符串的类型为const char*

尽管C++支持C风格字符串,但在C++程序中最好不要使用C风格的字符串。因为使用起来不方便,且容易引发程序漏洞。C风格字符串不是一种类型,而是为了表达和使用字符串而形成的一种约定俗成的写法。按照此习惯书写的字符串存放在字符数组中并以空字符结束。

12.3.2 Character Output Using Member Function put

basic_ostream的成员函数put,一次输出一个字符。例如:

cout.put('A');

会显示字符'A'。The put function also may be called with a numeric expression that represents an ASCII value, as in the following statement, which also outputs A:

cout.put(65);

12.4 流输入(Stream Input)

The stream extraction operator (>>) normally skips white-space characters (such as blanks, tabs and newlines) in the input stream.

12.4.1 get and getline 成员函数

>>运算符用空格分隔数据,即,在使用此运算符读取数据时,遇到空格就停止读取。

不带参数的 get 成员函数从指定的流中输入一个字符(包括空格字符和其他非图形字符,例如表示文件末尾的键序列),并将其作为函数调用的值返回。当在流上遇到文件末尾时,此版本的 get 将返回 EOF。EOF 通常具有值 –1,并在标头中定义,该标头通过流库标头间接包含在代码中<iostream>。

#include <iostream>
using namespace std;

int main() {
    int character; // **use int, because char cannot represent EOF**

// prompt user to enter line of text
    cout << "Before input, cin.eof() is "<<cin.eof()
       <<"\nEnter a sentence followed by Enter and end-of-file:\n";

    // use get to read each character; use put to display it
    while((character=cin.get())!=EOF){
        cout.put(character);
    }

    // display end-of-file character
    cout << "\nEOF in this system is: " << character
       <<"\nAfter input of EOF, cin.eof() is " <<cin.eof() << endl;
}

使用int类型的值,因为在许多平台上,char只能表示非负值,但是EOF为-1。

此外,我们还可以用输入输出流对象的一些成员函数来实现输入和输出。

  • cout.put()​输出单个字符,可以连续输出
  • cin.get()​读入一个字符(包括空白字符),返回读入成功的字符,如遇到文件结束符,返回 EOF
  • cin.get(ch)​读入一个字符并赋值给变量 ch,成功读入则返回真
  • cin.get​(字符数组或指针,字符个数 n,终止字符) 读入 n-1 个字符,如遇到终止字符则提前结束
  • cin.getline​(字符数组或指针,字符个数 n,终止字符) 与上面的 cin.get 类似,但是遇到终止字符时,字符指针会移到该终止字符后面,而 cin.get 则会停留在原位置
  • cin.eof()​如果到达文件末尾(遇文件终止符)返回真,否则返回假
  • cin.peek()​返回当前指针指向的字符,但只是观测,指针仍然停留在当前位置
  • cin.putback(ch)​将字符 ch 返回到输入流,插入到当前指针位置
  • cin.ignore​(n, 终止字符) 跳过输入流中 n 个字符,若遇到终止符提前结束,此时指向终止字符后面一个位置

get()函数是cin输入流对象的成员函数,cin.get()从流中读取并取走一个字符,有三种形式:

  1. 无参数的;
  2. 有一个参数的;
  3. 有3个参数的。

1.无参数的

其调用形式为

cin.get()

用来从指定的输入流中提取一个字符(包括空白字符),函数的返回值就是读入的字符。 若遇到输入流中的文件结束符,则函数值返回文件结束标志EOF(End Of File),一般以-1代表EOF,用-1而不用0或正值,是考虑到不与字符的ASCII代码混淆,但不同的C++系统所用的EOF值有可能不同。

#include <iostream>
using namespace std;

int main()
{
	char c;
	cout << "enter a sentence:" << endl;
	while ((c = cin.get()) != EOF){
		cout.put(c);
	}

	cout << "end" << endl;

	return 0;
}

2.有一个参数的

cin.get(ch)

其作用是从输入流中读取一个字符,赋给字符变量ch。如果读取成功则函数返回true,如失败(遇文件结束符) 则函数返回false(文件结束符 为 ctrl + z)。上面的例子可以改写如下:

#include <iostream>
using namespace std;

int main()
{
	char c;
	cout << "enter a sentence:" << endl;

	while (cin.get(c))//读取一个字符赋给字符变量c,如果读取成功,cin.get(c)为真
	                  //读取字符为文件结束符(Ctrl + z)时,cin.get(c)为假
	{
		cout.put(c);
	}
	cout << "end" << endl;

	return 0;
}

3.有三个参数的

    cin.get(字符数组, 字符个数n, 终止字符)
或
    cin.get(字符指针, 字符个数n, 终止字符)

其作用是从输入流中读取n-1个字符,赋给指定的字符数组(或字符指针指向的数组),如果在读取n-1个字符之前遇到指定的终止字符,则提前结束读取。如果读取成功则函数返回true(真),如失败(遇文件结束符) 则函数返回false(假)。如果在函数原型中省略终止字符,默认为'\n'。

具有三个参数(字符数组、大小限制和分隔符(具有默认值换行符))的成员函数 get 从输入流中读取字符,最多读(大小限制数目-1)个字符,或直到读取分隔符。输入字符串以 null 字符结尾。分隔符不放置在字符数组中,而是保留在输入流中。

将上例改写如下:

#include <iostream>
using namespace std;
int main()
{
	char ch[20];
	cout << "enter a sentence:" << endl;
	cin.get(ch, 10, '\n');//指定换行符为终止字符
	cout << ch << endl;
	system("pause");
	return 0;
}
#include <iostream>
using namespace std;

int main()
{
    // create two char arrays, each with 80 elements
    const int SIZE{80};
    char buffer1[SIZE];
    char buffer2[SIZE];

    // use cin to input characters into buffer1
    cout << "Enter a sentence:\n";
    cin >> buffer1;

    // display buffer1 contents
    cout << "\nThe string read with cin was:\n" << buffer1 << "\n\n";

    // use cin.get to input characters into buffer2
    cin.get(buffer2, SIZE);

    // display buffer2 contents
    cout << "The string read with cin.get was:\n" << buffer2 << endl;
}

cin​ 这个函数输入取数据的过程:

// cin如何读取
	int a, b;
	cin >> a >> b;

大家肯定知道,假定我们在这里输入3 5 8 9 11,a最终会读取的数字是 3。但是实际上cin是将3 5 8 9 11都放入了缓冲区,等待a去读取,a从头开始读,读到int类型的数据,并将3拿出来赋给a,这时候缓冲区内还剩下:5 8 9 11。注意:这里3后面的' '是存在的,缓冲区内的字符会一直留着直到后面被读取。然后接着b再读取,读到的是数字5,然后5便赋给b,剩下的字符留在缓冲区等待程序后续操作。

成员函数 getline的操作类似于三参数 get 成员函数。getline 函数从输入流中删除分隔符,但不将其存储在字符串中。

#include <iostream>
using namespace std;

int main(){
    const int SIZE{80};
    char buffer[SIZE]; // create array of 80 characters

    // input characters in buffer via cin function getline
    cout << "Enter a sentence:\n";
    cin.getline(buffer, SIZE);
  
    cout << "\nThe sentence entered is:\n" << buffer << endl;
}

12.4.2 istream Member Functions peek, putback and ignore

istream的成员函数ignore读取并舍弃字符。接收两个实参:

1.指定字符数-默认值为1

2.停止忽略字符的分隔符 - 默认分隔符为 EOF。

该函数将丢弃指定数量的字符,如果在输入流中遇到分隔符,则丢弃更少的字符。

它的原型是:

istream & ignore(int n =1, int delim = EOF);

此函数的作用是跳过输入流中的 n 个字符,或跳过 delim 及其之前的所有字符,哪个条件先满足就按哪个执行。两个参数都有默认值,因此 cin.ignore() 就等效于 cin.ignore(1, EOF), 即跳过一个字符。

例如:

ignore(6,'\n');

这里的意思是说从缓冲区的第一个字符开始读,读到第6个字符,这些字符我们就全部从缓冲区里舍去,假如这段字符长这样hello c++,那么现在缓冲区里还剩下c++,这里的字符是一个一个来的,假如是数字,例如:13 1 89 72,调用了cin.ignore(6,'\n')之后呢,缓冲区里还剩下9 72,没错,89变成了9,就是因为舍去的是前六位字符而不是数字,所以这里也是很多人容易错的地方,觉得是舍弃6个整数。
接着,看'\n',这个的意思就简单了,只要你输入了'\n',也就是我们键入回车的时候,ignore()便不再从缓冲区里舍弃字符了,也就是你回车之前的所有字符全部从缓冲区里拿出来。这个'\n'也可以定义为其他字符,只要遇到这个字符ignore()便停止他的行为。

//ignore()用法
#include <iostream>

using namespace std;

int main()
{
	int a, b;
	cin >> a; 
	//从缓冲区舍弃字符,到第五个停止,如果遇到换行符,舍弃换行符之前的所有字符
	cin.ignore(5, '\n'); 
	cin >> b;
	cout << "a is : " << a << endl;
	cout << "b is : " << b << endl;
	return 0;
}

输入25 86 91 12​,首先25​被a​从缓冲区中拿出来,此时缓冲区剩下 86 91 12​,然后开始舍弃,数到第五位,也就是91​中9​的位置,9​和它之前的数据被全部舍弃,b再进去读取,便读取到1​,输出正确。

这里我们在数字8后键入了回车,按照前面所说,a​拿走了25​,回车将8​以及它之前的数据全部丢掉,再给b进去读取,因此直接读取96

cin.ignore(),大可以把cin.ignore()理解为cin.ignore(1,'\n')​,就是舍弃掉第一个字符或者回车之前的数据,我们可以用它舍弃掉缓冲区里的空格字符或者存在的换行符。

// 代码差不多
#include <iostream>

using namespace std;

int main()
{
	int a, b;
	cin >> a;
	cin.ignore(); //唯一的区别在这!
	cin >> b;
	cout << "a is : " << a << endl;
	cout << "b is : " << b << endl;
	return 0;
}

putback成员函数将get函数从输入流中获取的上一个字符放回该流中。

peek成员函数返回输入流的下一个字符,但并不会将此字符从流中移除。

12.5 Unformatted I/O Using read, write and gcount

未格式化的输入/输出使用istream的read函数和ostream的write成员函数。read将字节放入char类型的数组中。write将char数组中的字节输出。例如:

char buffer[]{"HAPPY BIRTHDAY"}; 
cout.write(buffer, 10);

输出buffer中的前十个字节(包括空字符),

cout.write("ABCDEFGHIJKLMNOPQRSTUVWXYZ", 10);

上述代码将会输出字母表的前十个字母。

成员函数gcount报告上次输入操作读取的字符数量。

#include <iostream>
using namespace std;

int main(){
    const int SIZE{80};
    char buffer[SIZE];

    // use function read to input characters into buffer
    cout << "Enter a sentence:\n";
    cin.read(buffer, 20);

    // use functions write and gcount to display buffer characters
    cout << "\nThe sentence entered was:\n";
    cout.write(buffer, cin.gcount());
    cout << endl;
}

运行结果为:

12.6 Stream Manipulators(操纵符): 格式化输出

12.6.1 Integral Stream Base: dec, oct, hex and setbase

#include <iostream>
#include <iomanip>
using namespace std;

int main(){
    int number;

    cout<<"Enter a decimal number: ";
    cin >> number; // input number

    // use hex stream manipulator to show hexadecimal number
    cout << number << " in hexadecimal is: " << hex<< number << "\n";

    // use oct stream manipulator to show octal number
    cout << dec << number << " in octal is: " << oct << number << "\n";

    // use setbase stream manipulator to show decimal number
    cout << setbase(10)<< number << " in decimal is: " << number << endl;
}

12.6.2 设置浮点数精度(precision, setprecision)

使用setprecision流操作符或者ostream的成员函数precision控制浮点数的精度。使用setprecision流操作符会改变随后操作的浮点数的精度,直到下一次使用setprecision。使用成员函数precision会返回当前使用的浮点数的精度。头文件为<iomanip>

setprecision(0)的实际效果取决于编译器,不同的编译器实现是不同的。

#include <iostream>
#include <iomanip>
#include <cmath>
using namespace std;

int main(){
    double root2{sqrt(2.0)}; // calculate square root of 2

    cout << "Square root of 2 with precisions 0-9.\n"
       << "Precision set by ostream member function precision:\n";
    cout << fixed; // use fixed-point notation

    // display square root using ostream function precision
    for (int places{0}; places <= 9; ++places){
        cout.precision(places);
        cout << root2 << "\n";
    }

    cout << "\nPrecision set by stream manipulator setprecision:\n";

    // set precision for each digit, then display square root
    for (int places{0}; places <= 9; ++places){
        cout <<setprecision(places) << root2 << "\n";
    }
}

运行结果如下;

12.6.3 Field Width (width, setw)

istream和ostream类的成员函数width()设置field width(即,应输出值的字符位置数或应输入的最大字符数)。

If values output are narrower than the field width, fill characters are inserted as padding.A value wider than the designated width will not be truncated—the full number will be printed.The width function with no argument returns the current setting.

宽度设置仅适用于下一次插入或提取(即宽度设置not sticky);之后,将宽度隐式设置为 0(即,输入和输出将使用默认设置执行)。假设宽度设置适用于所有后续输出是一个逻辑错误。

如果输出的数值占用的宽度超过setw(int n)设置的宽度,则按照实际宽度输出。

float f=0.364823;
std::cout<<std::setw(3)<<f<<std::endl;

上述代码的输出结果为:

cout.width()默认为右对齐,且只对后面第一个输出有作用。

cin.width()遇到空格自动停止接收。例如对于下列代码,输入This is a test of the width member function。cin.width(5),遇到空格停止读入,所以只读入了This,使用cout.width(widthValue++)输出,widthValue先使用再递增,所以此时为cout.width(4)。

#include <iostream>
using namespace std;

int main(){
    int widthValue{4};
    char sentence[10];

    cout << "Enter a sentence:\n";
    cin.width(5); // input only 5 characters from sentence

    // set field width, then display characters based on that width
    while(cin>>sentence){
        cout.width(widthValue++);
        cout<<sentence<<"\n";
        cin.width(5);
    }
}

12.6.4 User-Defined Output Stream Manipulators

#include <iostream>
using namespace std;

// bell manipulator (using escape sequence \a)
ostream& bell(ostream& output){
    return output << '\a'; // issue system beep
}

// carriageReturn manipulator (using escape sequence \r)
ostream& carriageReturn(ostream& output){
    return output << '\r'; // issue carriage return
}

// tab manipulator (using escape sequence \t)
ostream& tab(ostream& output) {
    return output << '\t'; // issue tab
}

// endLine manipulator (using escape sequence \n and flush stream
// manipulator to simulate endl)
ostream& endLine(ostream& output){
    return output << '\n' << flush; // issue endl-like end of line
}

int main(){
    // use tab and endLine manipulators
    cout << "Testing the tab manipulator:" <<endLine
       <<'a'<<tab<<'b'<<tab<<'c'<<endLine;

    cout << "Testing the carriageReturn and bell manipulators:"
       <<endLine<<"..........";

    cout<<bell;//use bell manipulator

    // use carriageReturn and endLine manipulators
    cout << carriageReturn<< "-----" << endLine;
}

上述代码创建了自己定义的流操作符。

对于输出流操作符,返回类型和形参必须是ostream&类型。

12.7 格式化输出(Stream Format States and Stream Manipulators)

12.7.1 Trailing Zeros and Decimal Points (showpoint)

流操作符showpoint是一个sticky setting,强迫浮点数数字以其小数点和尾随零输出。例如,浮点数79.0输出为79,在不使用showpoint的情况下。或者使用showpoint输出79.00000。重置showpoint设置,使用流操作符noshowpoint。默认的浮点数精度为6,不使用fixed和scientific操作符,精度表示的是有效数字,而不是小数点以后的。例如9.9000,输出9.9。9.990输出9.99。例如下列程序:

#include <iostream>
using namespace std;

int main(){
    // display double values with default stream format
    cout << "Before using showpoint"
       <<"\n9.9900 prints as: " << 9.9900
       << "\n9.9000 prints as: " << 9.9000
       <<"\n9.0000 prints as: " << 9.0000;

    // display double value after showpoint
    cout<<showpoint
       <<"\n\nAfter using showpoint"
       <<"\n9.9900 prints as: " << 9.9900
       <<"\n9.9000 prints as: " << 9.9000
       <<"\n9.0000 prints as: " << 9.0000 << endl;
}

12.7.2 Justification (left, right and internal)

使用流操作符left或者right可以让要输出的内容在指定的宽度内左对齐或者右对齐。

#include <iostream>
#include <iomanip>
using namespace std;
int main() {
    int x{12345};

    // display x right justified (default)
    cout << "Default is right justified:\n\"" <<setw(10) << x << "\"";

    // use left manipulator to display x left justified
    cout << "\n\nUse left to left justify x:\n\""
         << left << setw(10) << x << "\"";

    // use right manipulator to display x right justified
    cout << "\n\nUse right to right justify x:\n\""
       << right << setw(10) << x << "\"" << endl;
}

流操作符internal指出数字的正负号(或者使用流操作符showbase显示数字使用的进制)应该在指定的输出宽度的最左边输出,数字的数量应该靠右显示。中间的空白区域使用填充字符填充,默认情况下为空格。showpos操作符使得正数的符号+强制显示。例如下述代码:

#include <iostream>
#include <iomanip>
using namespace std;

int main(){
// display value with internal spacing and plus sign
    cout<<internal<<showpos<<setw(10)<<123<<endl;
}


将123换成-123后,输出结果为:

对于指定的宽度10,数字-123,-号在最左面显示,123在最右边显示,中间以空格字符填充。

12.7.3 设置填充字符(fill, setfill)

对于指定的字段宽度,使用fill成员函数指定填充字符。默认情况下的填充字符为空格。函数返回先前的填充字符。setfill操作符也可以指定填充字符。

#include <iostream>
#include <iomanip>
using namespace std;

int main() {
    int x{10000};

    // display x
    cout << x << " printed as int right and left justified\n"
         << "and as hex with internal justification.\n"
         << "Using the default pad character (space):\n";

    // display x
    cout << setw(10) << x << "\n";

    // display x with left justification
    cout << left << setw(10) << x << "\n";

    // display x with base as hex with internal justification
    cout << showbase << internal<< setw(10) << hex << x << "\n\n";

    cout << "Using various padding characters:" << endl;

    // display x using padded characters (right justification)
    cout<<right;
    cout.fill('*');
    cout << setw(10) << dec << x << "\n";

    // display x using padded characters (left justification)
    cout << left << setw(10) <<setfill('%') << x << "\n";

    // display x using padded characters (internal justification)
    cout <<internal << setw(10) <<setfill('^') << hex << x << endl;
}

12.7.4 Integral Stream Base (dec, oct, hex, showbase)

C++提供流操作符dec,hex和oct让整数以十进制、十六进制和八进制的形式显示。如果没有指定以哪种进制显示,默认以十进制显示。以0开头的数字为八进制,以0x或者0X开头的数字为十六进制。

#include <iostream>
using namespace std;

int main(){
    int x{100};

    // use showbase to show number base
    cout << "Printing octal and hexadecimal values with showbase:\n"
       <<showbase;

    cout << x << endl; // print decimal value
    cout << oct << x << endl; // print octal value
    cout << hex << x << endl; // print hexadecimal value
}


​​​

12.7.5 Floating-Point Numbers; Scientific and Fixed Notation (scientific, fixed)

浮点值可以四舍五入到若干位有效数或精度,这是出现在小数点前后的总位数。可以通过使用 setprecision 操作符来控制显示浮点数值的有效数的数量。

// This program demonstrates how the setprecision manipulator
// affects the way a floating-point value is displayed.
#include <iostream>
#include <iomanip> // Header file needed to use setprecision
using namespace std;

int main()
{
    double number1 = 132.364, number2 = 26.91;
    double quotient = number1 / number2;
    cout << quotient << endl;
    cout << setprecision(5) << quotient << endl;
    cout << setprecision(4) << quotient << endl;
    cout << setprecision(3) << quotient << endl;
    cout << setprecision(2) << quotient << endl;
    cout << setprecision(1) << quotient << endl;
    return 0;
}

程序中的第一个值显示在第 11 行,没有设置 setprecision 操作符(默认情况下,系统使用 6 个有效数显示浮点值)。后续的 cout 语句打印相同的值,但四舍五入为 5、4、3、2 和 1 个有效数。

请注意,与 setw 不同的是,setprecision 不计算小数点。例如,当使用 setprecision(5) 时,输出包含 5 位有效数,但是需要 6 个位置来显示 4.9188。如果一个数字的值可以由少于 setprecision 指定的精度位数来表示,则操作符将不起作用。

使用流操作符scientific和fixed可以控制浮点数的输出格式。scientific强制浮点数以科学计数法的形式显示。

setprecision函数指明了浮点数应该显示的小数点后的位数,使用此函数,需要头文件。setprecision是一个parameterized stream manipulator。而endl是一个nonparameterized stream manipulator。
fixed指明浮点数的值应该显示为定点数,而不是科学计数法。fixed与setprecision(n)连用可以控制小数点后的位数。
当使用fixed和setprecision时,打印的值为四舍五入到由 setPrecision 的参数指示的小数位数,但内存中的值保持不变,例如87.946和67.543的输出分别为87.95和67.54,也可以使用showpoint和fixed实现上述功能,如果没有fixed,后面的零不会打印。例如7.3000会打印为7.3。

#include <iostream>
using namespace std;

int main(){
    double x{0.001234567};
    double y{1.946e9};

    // display x and y in default format
    cout << "Displayed in default format:\n" << x << '\t' << y;

    // display x and y in scientific format
    cout << "\n\nDisplayed in scientific format:\n"
            <<scientific << x << '\t' << y;

    // display x and y in fixed format
    cout << "\n\nDisplayed in fixed format:\n"
            << fixed<< x << '\t' << y << endl;  
}

12.7.6 Uppercase/Lowercase Control (uppercase)

uppercase流操作符可以让十六进制或者科学计数法显示数字时,使得原本是小写的字母变为大写。下例为未使用uppercase操作符之前:

#include <iostream>
using namespace std;

int main(){
    cout << "Printing uppercase letters in scientific\n"
       << "notation exponents and hexadecimal values:\n";

// use std::uppercase to display uppercase letters; use std::hex and
    // std::showbase to display hexadecimal value and its base
    cout << 4.345e10 << "\n"
       << hex << showbase << 123456789 << endl;
}

在使用uppercase操作符后:

#include <iostream>
using namespace std;

int main(){
    cout << "Printing uppercase letters in scientific\n"
       << "notation exponents and hexadecimal values:\n";

// use std::uppercase to display uppercase letters; use std::hex and
    // std::showbase to display hexadecimal value and its base
    cout <<uppercase<< 4.345e10 << "\n"
       << hex << showbase << 123456789 << endl;
}

12.7.7 Specifying Boolean Format (boolalpha)

C++提供了数据类型bool,其值可以是false的,也可以是true的,作为旧式的0表示假,任何非零值表示真的首选替代。布尔变量默认输出为0或1。可以使用流操作符boolalpha让输出流将bool值输出为字符串false或者true。使用noboolalpha使得bool值输出为整数(即,默认设置)。

#include <iostream>
using namespace std;

int main(){
    bool booleanValue{true};

    // display default true booleanValue
    cout << "booleanValue is " << booleanValue;

    // display booleanValue after using boolalpha
    cout << "\nbooleanValue (after using boolalpha) is "
       <<boolalpha<<booleanValue;

    cout << "\n\nswitch booleanValue and use noboolalpha\n";
    booleanValue = false; // change booleanValue
    cout << noboolalpha; // use noboolalpha

    // display default false booleanValue after using noboolalpha
    cout << "\nbooleanValue is " << booleanValue;

    // display booleanValue after using boolalpha again
    cout << "\nbooleanValue (after using boolalpha) is "
       <<boolalpha<<booleanValue<<endl;

}

12.7.8 Setting and Resetting the Format State via Member Function flags

在对要输出流进行了几次操作符的改动后,怎么才能恢复到默认格式呢?无实参的flag成员函数将当前的设置格式作为fmtflags格式返回,此格式代表格式状态。有实参的flags函数,以fmtflags格式为实参,将格式状态设置为fmtflags指明的格式,并返回先前的状态设置。

#include <iostream>
using namespace std;

int main(){
    int integerValue{1000};
    double doubleValue{0.0947628};

    // display flags value, int and double values (original format)
    cout << "The value of the flags variable is: " << cout.flags()
       <<"\nPrint int and double in original format:\n"
       <<integerValue << '\t' << doubleValue;

    // use cout flags function to save original format
    ios_base::fmtflags originalFormat{cout.flags()};
    cout << showbase << oct << scientific; // change format

    // display flags value, int and double values (new format)
    cout << "\n\nThe value of the flags variable is: "<<cout.flags()
       <<"\nPrint int and double in a new format:\n"
       <<integerValue << '\t' << doubleValue;

    cout.flags(originalFormat); // restore format

    // display flags value, int and double values (original format)
    cout << "\n\nThe restored value of the flags variable is: "
       <<cout.flags()<<"\nPrint values in original format again:\n"
       <<integerValue << '\t' << doubleValue << endl;
}

12.8 Stream Error States(流的错误状态)

每个流对象都包含一组状态比特以表示流的状态---sticky format settings,error indicators等。以下述代码为例:

#include <iostream>
using namespace std;

int main(){
    int integerValue;

    // display results of cin functions
    cout << "Before a bad input operation:"
       <<"\ncin.rdstate(): " <<cin.rdstate()
       <<"\n cin.eof(): "<<cin.eof()
       <<"\n cin.fail(): "<<cin.fail()
       <<"\n cin.bad(): "<<cin.bad()
       <<"\n cin.good(): "<<cin.good()
       <<"\n\nExpects an integer, but enter a character: ";

    cin >> integerValue; // enter character value

    // display results of cin functions after bad input
    cout << "\nAfter a bad input operation:"
       <<"\ncin.rdstate(): "<<cin.rdstate()
       <<"\n cin.eof(): "<<cin.eof()
       <<"\n cin.fail(): "<<cin.fail()
       <<"\n cin.bad(): "<<cin.bad()
       <<"\n cin.good(): "<<cin.good();

    cin.clear(); // clear stream

    // display results of cin functions after clearing cin
    cout << "\n\nAfter cin.clear()" << "\ncin.fail(): "<<cin.fail()
       <<"\ncin.good(): "<<cin.good()<<endl;
}

rdstate成员函数: 成员函数rdstate返回流中的错误状态。例如,通过调用cout.rdstate返回流的状态,然后通过switch语句检查eofbit、badbit、failbit 和 goodbit来检查这些状态。检测流状态的首选方法是使用成员函数eof, fial, bad 和 good, 使用这些函数不要求了解具体的状态位。

eof成员函数判定是否在流中遇到了end-of-file。在此例中,一开始没有输入任何内容,函数返回0(false)。此函数检查流的eofbit数据成员的值,该值在输入流遇到文件结束符后被设置为真。Returns true if the associated stream has reached end-of-file.Specifically, returns true if eofbit​ is set in rdstate() .此函数仅报告最近 I/O 操作设置的流状态;它不检查关联的数据源。例如,最近的I/O操作是get(),get()函数返回文件的最后一个字节,eof()返回false。下一个get()函数从输入流中不会提取到任何字符,并且会设置eofbit.只有这样,eof()才会返回true。

#include <cstdlib>
#include <fstream>
#include <iostream>
 
int main()
{
    std::ifstream file("test.txt");
    if (!file) // operator! is used here
    {  
        std::cout << "File opening failed\n";
        return EXIT_FAILURE;
    }
 
    // typical C++ I/O loop uses the return value of the I/O function
    // as the loop controlling condition, operator bool() is used here
    for (int n; file >> n;)
       std::cout << n << ' ';
    std::cout << '\n';
 
    if (file.bad())
        std::cout << "I/O error while reading\n";
    else if (file.eof())
        std::cout << "End of file reached successfully\n";
    else if (file.fail())
        std::cout << "Non-integer data encountered\n";
}

fail成员函数判定一个流操作是否失败。此函数检查流的failbit数据成员,Returns true if an error has occurred on the associated stream.当在流中发生格式错误时,failbit位将被设置。例如程序要求输入整数,但是在输入流中有非整数的字符的情况。在遇到这种错误时,这些字符不会丢失。成员函数fail将报告流操作失败了,通常这种错误是可以恢复的。

#include <cstdlib>
#include <fstream>
#include <iostream>
 
int main()
{
    std::ifstream file("test.txt");
    if (!file) // operator! is used here
    {  
        std::cout << "File opening failed\n";
        return EXIT_FAILURE;
    }
 
    // typical C++ I/O loop uses the return value of the I/O function
    // as the loop controlling condition, operator bool() is used here
    for (int n; file >> n;)
       std::cout << n << ' ';
    std::cout << '\n';
 
    if (file.bad())
        std::cout << "I/O error while reading\n";
    else if (file.eof())
        std::cout << "End of file reached successfully\n";
    else if (file.fail())
        std::cout << "Non-integer data encountered\n";
}

bad成员函数:判定流操作是否失败。当发生数据丢失时,将会设置badbit位。成员函数bad将报告流操作是否失败了。一般情况下,这种严重的错误是不能修复的。

good成员函数: 如果流中的eofbit、failbit 和 badbit位都没有被设置,那么goodbit位将被设置,即如果函数eof, fail 和 bad都返回false值,则成员函数good返回true值。I/O操作只在“好的”流中才能进行。

clear成员函数: clear成员函数将流的状态重置为“好的”,使得流可以继续执行I/O操作。clear函数的默认参数是goodbit ,所以语句cin.clear()清空了cin, 并且为该流设置goodbit位。语句cin.clear(ios::failbit)则为流设置failbit位。

如果failbit位 和 badbit位其中至少一个被设置, 则basic_ios的成员函数operator!返回true;operator void*返回false值(0)

重载!和bool

重载运算符可用于测试流在条件下的状态。operator!成员函数返回true如果badbit和failbit其一为true,或者两者均为true。如果badbit为真,failurebit为真或两者都为真,则operator bool成员函数返回false。当在选择语句或迭代语句的控制下测试真/假条件时,这些函数在 I/O 处理中非常有用。例如下列语句:

if(!cin){
    //process invalid input stream
}

如果cin的流由于输入失败而无效,则执行代码。或者:

while(cin>>variableName){
    //process valid input
}

只要每个输入操作都成功,就可以执行循环,并在输入失败或遇到end-of-file时终止循环。

标签:字符,12,cout,int,输入输出,cin,char,include
From: https://www.cnblogs.com/yyyylllll/p/18390196

相关文章

  • 【安全运营】安全自动化协议SCAP及其12大组件介绍
    一、SCAP产生背景二、SCAP简介三、SCAP12大组件介绍四、已经支持SCAP的安全工具五、参考链接原创全栈安全由于计算机和网络技术的快速发展,越来越多的软件和系统被应用到企业和机构中,这些软件和系统的安全问题也日益凸显。传统的安全措施,如防火墙、入侵检测等,已经......
  • 信奥赛一本通陈老师解题 1123:图像相似度
    ​【题目描述】给出两幅相同大小的黑白图像(用0-1矩阵)表示,求它们的相似度。说明:若两幅图像在相同位置上的像素点颜色相同,则称它们在该位置具有相同的像素点。两幅图像的相似度定义为相同像素点数占总像素点数的百分比。【输入】第一行包含两个整数m和n,表示图像的行数和列数,......
  • day12打卡
    平衡二叉树classSolution{public:intgetheight(TreeNode*root){if(root==nullptr){return0;}intleft=getheight(root->left);intright=getheight(root->right);return1+max(left,right);}boolisBalanced(TreeNode*root){if(root==nullptr)......
  • 信奥赛一本通陈老师解题 1128:图像模糊处理
    ​ 【题目描述】给定n行m列的图像各像素点的灰度值,要求用如下方法对其进行模糊化处理:1.四周最外侧的像素点灰度值不变;2.中间各像素点新灰度值为该像素点及其上下左右相邻四个像素点原灰度值的平均(舍入到最接近的整数)。【输入】第一行包含两个整数n和m,表示图像包含像素......
  • [COCI2012-2013#2] INFORMACIJE 题解
    前言题目链接:洛谷。题意简述你需要构造一个\(1\simn\)的排列\(a\),满足\(m\)个条件,格式如下:1xyv:\(\max\limits_{i=l}^ra_i=v\)。2xyv:\(\min\limits_{i=l}^ra_i=v\)。题目分析首先这个最值很难受,考虑能不能转化成我们喜欢的二元关系......
  • CMake构建学习笔记12-libzip库的构建
    如果要更方便地压缩/解压缩文件或者文件夹,除了使用基于zlib的minizip库,更推荐使用另一个基于zlib的库libzip,个人认为其接口设计更科学一点,文档也更丰富一点。不过libzip库本身的构建倒是没什么特别的,关键指令如下所示:#配置CMakecmake..-G"$Generator"-Ax64`-DCMAK......
  • 51nod 1204 Parity
    闲话虽然这题好像找不到原题了,但毋庸置疑地说这的确是并查集的好题。分析可以先对奇偶区间进行分析,当这个有偶数个1时,区间\(1-(left-1)\)一定与区间\(1-right\)的奇偶性相同。如此图\(3-4\)为偶区间,根据分析,\(1-2\)为奇区间。\(1-4\)也为奇区间。但如果填入的......
  • 【MySQL 12】事务管理 (带思维导图)
    文章目录......
  • 2024-08-30 error [email protected]: The engine "node" is incompatible with this m
    删掉依赖,使用yarn重新拉取,保错如下:[email protected]:Theengine"node"isincompatiblewiththismodule.Expectedversion">=18".Got"16.19.1" 错误[email protected]:引擎“节点”与此模块不兼容。预期版本“>=18”。得到“16.19.1”意思就是yarn拉取依赖过程中......
  • 大功率舞台灯调光调色方案 | 支持深度调光,多路输出调光 36V/48V/60V FP7126
    在舞台演出中,灯光扮演着非常重要的角色,它不仅可以烘托氛围,营造氛围,更能够为表演者增添光彩,塑造形象。在博物馆场所中,突出展品细节。根据灯光用途和适用类型,舞台灯可以细分为聚光灯、泛光灯、效果灯具等。在舞台照明行业,高功率舞台灯所需的稳定电源供应至关重要。此次方案以3......