当前位置:   article > 正文

C++:字符(串)输入和输出_c++字符串的输入输出

c++字符串的输入输出


1. 流和缓存

C++程序把输入和输出当作字节流,对于面向文本的程序,每个字节对应一个字符。流stream充当程序与流的起点或终点之间的媒介,连接程序端与文件端。文件端可以是文件,也可以是设备,比如键盘和屏幕。

缓存buffer是一块内存,充当程序与设备之间信息交换的临时存储1。一般地,设备,比如硬盘,通常以512字节(或更多)为单位传输信息,而程序每次处理一个字节信息。而且,从内存中读单个字节,比从硬盘中更快。缓存帮助匹配两个不同速率的数据交换:从硬盘中读取一块数据,保存在缓存中,再从缓存中每次读取一个字节,读完后(清空缓存flush the buffer)再从硬盘取一块数据放到缓存;反方向,向缓存每次写入一个字节,写满缓存后再一次性写入硬盘(清空缓存),然后再向缓存写入数据。缓存法比单字节读写法(byte-by-byte)更快和更简单。

在将输入数据传给程序前,缓存法键盘输入允许用户备份和修改输入信息。通常,C++程序在用户按下回车键Enter时清空输入缓存,当用户输出换行符(newline character)时清空输出缓存,都不必等到缓存填满。

2. 标准输入和输出流

C++提供了多个类来实现和管理流和缓存:

类 class描述
streambuf为缓存提供内存,并一同提供用于填充缓存、访问缓存内容、清空缓存和管理缓存内存的类方法。
ios_base表示流的一般属性,比如是否打开用于读取和是二进制流还是文本流。
ios基于ios_base class,包括一个指向streambuf对象的指针成员。
ostream衍生自ios,提供输出方法。
istream衍生自ios,提供输入方法。
iostream基于istream和ostream,继承两者的输入和输出方法。

在C++程序中包括头文件<iostream>(在该头文件中声明的对象有外部链接性external linkage和静态生存期static duration2)将自动创建8个流对象(窄字符34个,宽字符44个):

  1. cin对应标准输入流(standard input stream):默认与标准输入设备(一般是键盘)相关联。
  2. cout对应标准输出流(standard output stream):默认与标准输出设备(一般是显示器)相关联。
  3. cerr对应标准错误流(standard error stream):默认与标准输出设备(一般是显示器)相关联,而且该流不缓存,直接把错误信息发送到屏幕,不等缓存填满或换行符(newline character)。
  4. clog对应标准错误流(standard error stream):默认与标准输出设备(一般是显示器)相关联,而且缓存。
C streamC++ stream默认关联设备缓存
stdincin键盘
stdoutcout显示器
stderrcerr显示器
clog显示器

默认cinstdin同步,coutstdout同步。cin绑定于cout,意味着在对cin执行I/O操作之前先清空cout缓存。而cout不与任何其他输出流绑定。

3. 字符输入和输出

#include <istream>
// single character
int get(void);              // return character read or EOF if failure
istream & get(char & c);    // return invoking object reference

#include <ostream>
// single character
ostream & put(char c);      // return invoking object reference
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

get()函数有三种模式:单字节模式(见上面代码片段)、C风格字符串模式和流缓存模式。而且字符输入所使用单字节模式也有两种签名:第一种签名与C语言字符输入的gtechar函数等价,无参数,返回读取的字符,如果出错返回EOF;第二种签名与put()函数的一致,将读取的字符赋值给引用参数所指示的char型变量,返回调用对象引用,所以支持输入级联(concatenation)。

#include <iostream>

using namespace std;

int main(int argc, char const *argv[]) {
    char a;
    char b;
    char c;
    cout << "Enter no less than 3 characters: \n";
    a = cin.get();      // int get(void)
    cin.get(b).get(c);  // istream & get(char & c)
    cout.put(a).put(b).put(c).put('\n');    // ostream & put(char c)
    return 0;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

输出

Enter no less than 3 characters: 
RMB
RMB
  • 1
  • 2
  • 3

4. 字符串输入和输出

#include <istream>
// append '\0' at the end, leave delimiter in queue
istream & get(char * s, streamsize n, char delim='\n');
// append '\0' at the end, discard delimiter
istream & getline(char * s, streamsize n, char delim='\n');
// without checking its content nor appending '\0' at the end
istream & read(char * s, streamsize n);

#include <ostream>
// without checking its content and treat '\0' as regular character
ostream & write(const char * s, streamsize n);
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

get()getline()读取字符串,直到遇到EOF、分隔符或者已经读取n-1个字符,无论哪个先发生。

输入函数默认分隔符处理分隔符结尾无效字符’\0’
get‘\n’留在队列中添加
getline‘\n’丢弃添加
read不添加

四个函数都是返回调用对象的引用,支持级联。read()write()函数读写一块数据,read()从输入流中提取n个字符保存在字符数组中,write()将字符数组中的前n个字符插入到输出流中,都不对内容进行检查,不对无效字符做特殊处理。

#include <iostream>
#include <fstream>  // file stream
#include <cstring>  // strlen

using namespace std;

int main(int argc, char const *argv[]) {
    ifstream fin("1.txt", ios_base::in);    // the same as cin
    int n = 13;
    char s1[n];
    char s2[n];
    char s3[n];

    cout << "Enter a string for s1[13]:\n";
    // hello, world\n
    fin.get(s1, n, '\n');       // leave delimiter in queue
    char a = fin.get();         // delimiter '\n'
    cout << "strlen(s1): " << strlen(s1);
    cout.put(a);                // newline '\n'
    cout << s1 << a;

    cout << "Enter a string for s2[13]:\n";
    // hello, world\n
    fin.getline(s2, n, '\n');   // discard delimiter
    cout << "strlen(s2): " << strlen(s2) << '\n';
    cout << s2 << '\n';

    cout << "Enter a string for s3[13]:\n";
    // hello, world!!!\n
    fin.read(s3, n-3);          // no appending '\0' at the end
    cout << "strlen(s3): " << strlen(s3) << '\n';

    cout << "output s3 using cout.writer(s3, 13):\n";
    cout.write(s3, n) << '\n';

    cout << "output s3 using cout << s3 << '\\n':\n";
    cout << s3 << '\n';

	fin.close();	// close text file
    return 0;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41

文本文件"1.txt"

hello, world
hello, world
hello, world!!!

  • 1
  • 2
  • 3
  • 4

输出

Enter a string for s1[13]:
strlen(s1): 12
hello, world
Enter a string for s2[13]:
strlen(s2): 12
hello, world
Enter a string for s3[13]:
strlen(s3): 13
output s3 using cout.writer(s3, 13):
hello, wor_<0x04><0x01>
output s3 using cout << s3 << '\n':
hello, wor_<0x04><0x01>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

以上代码示例将文本文件"1.txt"与文件输入流对象ifstream fin相关联,使用fin读取字符串,与使用标准输入流cin等价。也可以对cin重定向,在命令行输入./a.out < 1.txt,在代码中使用cin,产生相同效果。

5. 格式化输入和输出

对位移运算符<<(左移)和>>(右移)进行重载,得到用于输出cout的插入insertion运算符和用于输入的提取extraction运算符。提取运算符可以识别字符数组、字符指针和string class对象三种类型变量,用于保存读取的字符串,而且读取时跳过空白字符。空白字符whitespace character通常包括空格符space、制表符tab和换行符newline三种,更广义的空白字符如下表2,可以用头文件<cctype>里的int isspace(int c)函数来检查。插入运算符接收到字符数组名或者字符指针后,利用字符串末尾无效字符决定何时停止显示字符。

字符数值(16进制)名称
’ ’(0x20)space (SPC)
‘\t’(0x09)horizontal tab (TAB)
‘\n’(0x0a)newline (LF)
‘\v’(0x0b)vertical tab (VT)
‘\f’(0x0c)feed (FF)
‘\r’(0x0d)carriage return (CR)

清空缓冲的四种情况:

  1. 缓存填满。
  2. 回车键Enter和换行符'\n'
  3. cin绑定于cout,在对cin执行I/O操作之前先清空cout缓存。
  4. <ostream>里的操作符(manipulator,也是函数):flush(只清空缓存)和endl(先换行,再清空缓存)。
#include <ostream>
ostream & flush(ostream & os);
ostream & endl(ostream & os);
  • 1
  • 2
  • 3

代码示例

#include <iostream>
#include <string>   // string class

using namespace std;

int main(int argc, char const *argv[]) {
    int n = 13;
    char a[n];              // char array
    char * b = new char[n]; // char pointer,allocate memory
    string str;             // string class object
    cin >> a;
    cin >> b;
    cin >> str;
    cout << a << endl;
    cout << b << '\n' << flush;
    cout << str;
    cout.put('\n');
    flush(cout);                // no '\n', fluch buffer only
    cout << "hello, world";
    endl(cout);                 // '\n' then flush buffer
    delete b[];                 // free memory
    return 0;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23

输出

good morning, beijing
good
morning,
beijing
hello, world
  • 1
  • 2
  • 3
  • 4
  • 5

6. string class 输入

除了使用提取运算符>>将字符串保存到string class对象,还可以使用<string>里的getline()函数,从输入流is中读取一行字符串保存到str中,默认分隔符是换行符’\n’(提取后丢弃分隔符)。使用string class的构造函数string(const char * s)从C风格字符串构造一个等价的string class对象,相应地使用其成员函数c_str()返回等价的C风格字符串。另外一个构造函数string(const char * s, size_t n);可以指明需要拷贝的字符个数。

#include <string>
// get a line from istream into a string object, automatic sizing feature
istream & getline(istream &  is, string & str, char delim='\n');
// construct a string object from c-string (null-terminated char sequence)
string(const char * s); // constructor
// construct a string object from buffer, copy the first n chars from array
string(const char * s, size_t n);	// constructor
// get c-string equivalent (plus a terminating null character '\0')
const char * c_str() const noexcept;
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

代码示例

#include <iostream>
#include <cstdio>   // printf
#include <cstring>  // strlen

using namespace std;

int main(int argc, char const *argv[]) {
    string str1;
    getline(cin, str1, '!');
    cout << str1 << '\n';
    cout << "str1.size(): " << str1.size() << '\n';

    const char * cstr = str1.c_str();
    printf("%s\n", cstr);
    printf("strlen(cstr): %lu\n", strlen(cstr));

    string str2(cstr, strlen(cstr) - 3);
    cout << str2 << '\n';
    return 0;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20

输出

hello, world!
hello, world
str1.size(): 12
hello, world
strlen(cstr): 12
hello, wo
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

7. 文件输入和输出

<fstream>衍生自<iostream>,其中的open()函数可以创建输入流ifstream和输出流ofstream对象,与具体文件相关联,使用方式与标准输入流cin和标准输出流cout一样。相应地,使用其成员函数close()断开文件与文件流对象的连接,而文件流对象和它管理的缓存还在,可以重新使用与其他文件建立连接1

#include <fstream>

#include <ifstream>
void open(const   char * filename,  ios_base::openmode mode = ios_base::in);
void open(const string & filename,  ios_base::openmode mode = ios_base::in);

#include <ofstream>
void open(const   char * filename,  ios_base::openmode mode = ios_base::out);
void open(const string & filename,  ios_base::openmode mode = ios_base::out);
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

代码示例

#include <iostream>
#include <fstream>
#include <string>

using namespace std;

int main(int argc, char const *argv[]) {
  ifstream fin;
  fin.open("1.txt", ifstream::in);
  ofstream fout("2.txt", ios_base::out);
  string str;
  fin >> str;
  fout << "hey, there\n";
  fout << str << '\n';
  fin.close();
  fout.close();
  return 0;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18

文本文件"1.txt"

hello, world

  • 1
  • 2

文本文件"2.txt"(初始为空)

hey, there
hello,

  • 1
  • 2
  • 3

  1. C++ Primer Plus 6th Edition by Stephen Prata ↩︎ ↩︎

  2. www.cplusplus.com ↩︎ ↩︎

  3. 传统的8比特字符ASCII类型char↩︎

  4. 大于8比特的字符类型wchar_t,C++11添加了char16_tchar32_t↩︎

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/AllinToyou/article/detail/252536
推荐阅读
相关标签
  

闽ICP备14008679号