IO

  • C++中数据输入/输出操作是通过I/O流库实现

  • 流:数据之间的传输操作

    • 输出流:数据从内存中传送到某个载体、设备中
    • 输入流:数据从某个载体、设备传送到内存缓冲区
  • C++中流类型

    • 标准流I/O流:内存与标准输入、输出设备之间信息传递
    • 文件I/O流:内存与外部文件之间信息传递
    • 字符串I/O流:内存变量与表示字符串流的字符数组 之间信息传递

<ios>

class ios

ios:流基类

  • 所有流的父类
  • 保存流状态、处理错误

方法

  • .fail():判断流是否失效

    • 尝试超出文件的结尾读取数据时
    • 输入流中字符串无法被正确解析
  • .eof():判断流是否处于文件末尾

    • 基于C++流库语义,.eof方法只用在.fail调用之后, 用于判断错故障是否是由于到达文件结尾引起的
  • .clear():重置与流相关状态位

    • 故障发生后,任何时候重新使用新流都必须调用此函数
  • if(stream):判断流是否有效

    • 大部分情况下等同于if(!stream.fial())
  • .open(filename):尝试打开文件filename并附加到流中

    • 流方向由流类型决定:输入流对于输入打开、输出流对于 输出打开
    • 可以调用.fail判断方法是否失败
  • .close():关闭依附于流的文件

.[un]setf
1
2
UKNOWN setf(setflag, unsetfield);
UKNOWN unsetf(unsetflag);
  • 用途

    • .setf:设置某个流操纵符
    • .unsetf():取消某个流操纵符
  • 参数

    • setflag:需要设置的操纵符
    • unsetflag:取消设置的操纵符
    • unsetfield:需要清空的格式设置位组合
  • 不能像<<>>中省略操纵符ios::前缀
.rdbuf
1
2
3
4
5
6
7
8
9
10
11
12
13
14
template <class Elem, class Traits>
class basic_ios: public ios_base{
basic_streambuf <_Elem, _Traits> *_Mystrbuf,

_Mysb * rdbuf() const{
return (_Mystrbuf);
}

_Mysb * rdbuf(_Mysb * _Strbuf){
_Mysb * _Oldstrbuf = _Mystrbuf;
_Mystrbuf = _Strbuf;
return (_Oldstrbuf);
}
}
  • 用途:获得输入、输出流对象中指向缓冲区类streambuf指针
    • >><<操作符对其有重载,可以方便读取、写入

class istream

istream:输入流基类

  • 将流缓冲区中数据作格式化、非格式化之间的转换
  • 输入

方法

  • .unget():复制流的内部指针,以便最后读取的字符能再次 被下个get函数读取
.get
1
2
3
4
5
6
int_type get();
basic_istream& get(E& c);
basic_istream& get(E *s, streamsize n);
basic_istream& get(E *s, streamsize n, E delim);
basic_istream& get(basic_stream<E, T> &sb);
basci_istream& get(basci_stream<E, T> &sb, E delim);
  • 用途:从输入流中获取字符、字符串

  • 参数

    • delim:分隔符,缺省\n
    • n

(友元)函数

getline
1
2
3
4
5
6
7
8
9
10
11
12
template<class E, class T, class A>
basic_istream<E, T>& getline(
basic_istream<E, T>& is,
basic_string<E, T, A>& str,
);

template<class E, class T, class A>
basic_istream<E, T>& getline(
basic_istream<E, T>& is,
basic_string<E, T, A>& str,
E delim,
);
  • 用途:从流is读取以delim为界,到字符串中

    • 保留开头空白字符、丢弃行尾分割符
    • 读取字符直到分隔符,若首字符为分隔符则返回空字符串
  • 参数

    • delim:分隔符,缺省为换行符\n

class ostream

ostream:输出流基类

  • 将流缓冲区中数据作格式化、非格式化之间的转换,输出

方法

  • .put(ch):将字符ch写入输出流

class iostream

iosstream:多目的输入、输出流基类

Operator

Insertion Operator

<<:插入操作符,将数据插入流中

  • 左操作数是输出流

  • 右操作数是需要插入流中的数据

    • 基本类型:<<会将其自动转换为字符串形式

      • 整形:默认10进制格式
      • [unsigned ]char类型:总是插入单个字符
    • streambuf类型指针:插入缓冲区对象中所有字符

Extraction Operator

>>:提取操作符,从输入流中读取格式化数据

  • 左操作数为输入流

  • 右操作数存储从输入流中读取的数据

    • 缺省

      • skipws:忽略开头所有空白字符
      • 空白字符分隔:读取字符直到遇到空白字符
    • streambuf类型指针:把输入流对象中所有字符写入该 缓冲区

  • 几乎不提供任何支持检测用户输入是否有效的功能
    • 数据格式由变量类型控制

缓冲

缓冲类型

  • ISO C要求
    • 当且仅当不涉及交互设备时,标准输入、输出全缓存
    • 标准错误绝不是全缓存
  • 无缓冲:不缓冲字符

    • 适用情况:标准错误

    • 标准库不缓冲不意味着系统、设备驱动不缓冲

  • 行缓冲:在输入、输出遇到换行符时才会执行I/O操作

    • 适用情况:涉及交互设备,如标准输入、输出
  • 全缓冲:I/O操作只会在缓冲区填满后才会进行

    • 适用情况:大部分情况,如驻留在磁盘的文件

    • flush描述I/O缓冲写操作

      • 标准I/O函数自动flush
      • 手动调用对流调用死fflush函数
  • 缓冲区一般是在第一次对流进行I/O操作时,由标准I/O函数调用 malloc函数分配得到

文件自定义缓冲区

  • 文件必须已打开、未做任何操作
setbuf
1
void setbuf(FILE * restrict fp, char * restrict buf);
  • 用途:打开或关闭缓冲区
    • 打开:buf必须为大小为BUFSIZ的缓存
      • BUFSIZ:定义在stdio.h中,至少256
    • 关闭:将buf设置为NULL
setvbuf
1
2
int setvbuf(FILE * restrict fp, char * restrict buf,
int mode, size_t size);
  • 用途:设置缓冲区类型

流自定义缓冲区

setbuf
1
virtual basic_streambuf * setbuf(E *s, streamsize n);

Manipulator

(流)操纵符:控制格式化输出的一种特定类型值

输出

  • 短暂的:只影响下个插入流中的数据
  • 持久的:直到被明确改变为止

  • 双操纵符条目中,前者为默认

  • setwsetprecisionsetfill还需要包含<iomanip>

组合格式

  • adjustfield:对齐格式位组合
  • basefield:进制位组合
  • floatfield:浮点表示方式位组合

位置

  • endl:将行结束序列插入输出流,确保输出字符被写入目的流
  • setw(n):短暂的
  • setfill(ch):持久的,指定填充字符,缺省空格
  • left:持久的,指定有效值靠左
  • right:持久的,指定有效值靠右
  • internal:持久的,指定填充字符位于符号、数值间

数值

  • showbase:为整数添加表示其进制的前缀
  • fixed:持久的,完整输出浮点数
  • scientific:持久的,科学计数法输出浮点数
  • setprecision(digits):持久的,精度设置依赖于其他设置

    • fixed/scientific:指定小数点后数字位数
    • 其他:有效数字位数
  • hex:持久的,16进制输出无符号整形

  • oct:持久的,8进制输出无符号整形
  • dec:持久的,10进制输出整形

  • noshowpoint/showpoint:持久的,否/是强制要求包含 小数点

  • noshowpos/showpos:持久的,要求正数前没有/有+
  • nouppercase/uppercase:持久的,控制作为数据转换部分 产生任意字符小/大写,如:科学计数法中的e
  • noboolalpha/boolalpha:持久的,控制布尔值以数字/ 字符形式输出

控制

  • unitbuf:插入、提取操作之后清空缓冲
  • stdio:每次输出后清空stdout、stderr

输入

  • skipws/noskipws:持久的,读取之前是/否忽略空白字符
  • ws:从输入流中读取空白字符,直到不属于空白字符为止

<iostream>

  • ifstream_withassign:标准输入流类

    • cin:标准文件stdin
  • ofstream_withassign:标准输出、错误、log流

    • cout:标准文件stdout
    • cerr:标准文件stderr
    • clog:标准文件stderr

<fstream>

  • ifstream:文件输入流类

    • 默认操作:ios::in
  • ofstream:文件输出流类

    • 默认操作:ios::out|ios::trunc
  • fstream:文件流输入、输出类

1
2
3
4
5
6
7
8
9
10
11
12
13
#include <fstream>

int main(){
ifstream infile;
ofstream outfile;
// 声明指向某个文件的流变量

infile.open(filename)
// 打开文件:在所声明变量和实际文件间建立关联

infile.close()
// 关闭文件:切断流与所关联对象之间联系
}

流操作复制文件

  • 逐字符复制

    1
    2
    3
    4
    5
    6
    7
    #include<fstream>
    std::ifstream input("in", ios::binary);
    std::ofstream output("out", ios::binary);
    char ch;
    while(input.get(ch)){
    output << ch;
    }
    • 使用input >> ch默认会跳过空白符,需要使用 input.unsetf(ios::skipws)取消
  • 逐行复制

    1
    2
    3
    4
    5
    #include<string>
    std::string line;
    while(getline(input, line)){
    output << line << "\n";
    }
    • 若文件最后没有换行符,则复制文件会末尾多\n
  • 迭代器复制

    1
    2
    3
    4
    5
    6
    #include<iterator>
    #include<algorithm>
    input.unsetf(ios::skipws);
    copy(istream_iterator(input), istream_iterator(),
    ostream_iterator(output, "")
    );
  • 缓冲区复制

    1
    output << input.rdbuf();
    • 丢失\n

标准输出文件内容

  • <<操作符

    1
    2
    3
    4
    5
    #include<iostream>
    #include<fstream>

    ifstream input("in");
    cout << input.rdbuf();
  • .get方法

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    while(input.get(*cout.rdbuf()).eof()){
    // 读取一行
    if(input.fail()){
    // `get`遇到空行无法提取字符,会设置失败标志
    input.clear();
    // 清除错误标志
    }
    cout << char(input.get());
    // 提取换行符,转换为`char`类型输出
    }
  • .get方法2

    1
    input.get(*cout.rdbuf(), EOF);

<sstream>

  • 基于C类型字符串char *编写

    • istrstream:串输入流类
    • ostrstream:串输出流类
    • strstream:串输入、输出流类
  • 基于std::string编写:推荐

    • istringstream:串输入流类
    • ostringstream:串输出流类
    • stringstream:串输入、输出流类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#include <sstream>

int string_to_integer(string str){
instringstream istream(str)
// 类似`ifstream`,使用流操作符从字符串中读取数据
int value;

istream >> value >> ws;
// `>>`忽略流开头空白字符,`ws`读取尾部空白
if(stream.fail() || !stream.eof()){
// 如果字符串不能作为整数解析,`.fail`返回`true`
// `.eof`返回`false`,说明字符串包含其他字符
error("string to integer: illegal integer format");
}
return value;
}

string integer_to_string(int n){
ostringstream ostream;
ostream << n;
return stream.str();
//
}

STL 其他

STL 线代

选择函数

简单多态函数

  • max(x,y)
  • min(x,y)
  • swap(x,y)
  • iter_swap(x,y)

迭代范围内操作

  • binary_search(begin, end, value):若迭代返回内包含指定 value,返回true
  • copy(begin, start, out):将指定迭代范围内值拷贝给out 开始的迭代器
  • count(begin, end, value):返回迭代范围内与指定value 值相等的数目
  • fill(begin, end, value):将指定迭代范围内元素值置为 value
  • find(begin, end, value):返回指定范围内首个与value值 相同的元素的迭代器,不存在则结束
  • merge(begin_1, end_2, begin_2, end_2, out):将两个有序 子序列合并为一个以out开始的完整有序序列
  • inplace_merge(begin, middle, end):合并同一个集合内的 两个子序列
  • min_element(begin, end):返回指向迭代范围中最小元素的 迭代器
  • max_element(begin, end):返回指向迭代范围中最大元素的 迭代器
  • random_shuffle(begin, end):随机重排迭代范围中的元素
  • replace(begin, end, old, new):将迭代范围中的所有old 替换为new
  • reverse(begin, end):逆序指定迭代范围中元素
  • sort(begin, end):将迭代范围中元素升序排列

包含函数参数

  • 函数参数可以是函数对象、函数指针
  • for_each(begin, end, fn):对迭代范围中每个元素调用fn
  • count_if (begin, end, pred):计算迭代范围内pred返回 true数目
  • replace_if(begin, end, pred):将迭代范围内pred返回 true所有值替换为new
  • partition(begin, end, pred):将所有pred返回true 元素放在开头,返回指向边界的迭代器

集合类

Vector

Vector类提供了类似数组功能的机制,并对C++中数组做出了改进

  • 数组参见cppc/mem_ctl

API

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
Vector<int> vec;
// 创建Vector对象
Vector<int> vec(VEC_LEN);
// 创建确定长度Vector对象长度,并将值初始化为0

vec.add(10);
// 在Vector对象里面添加新元素
vec.insert(2, 30);
// 向Vector对象中index=2插入元素
vec.remove(0)
// 删除Vector对象中index=0处元素
vec.set(3, 70)
vec[3] = 70
// 改变Vector对象中index=3处元素
// `[]`方法简短、和数组操作更相似,Vector被设计模仿

构造函数

  • Vector<type>()
  • Vector<type>(n, value):创建含有n个对象Vector元素, 每个元素都被初始化为value,缺省为相应类型默认值

方法

  • .size()
  • .isEmpty()
  • .get(index)
  • .set(index, valu)
  • .add(value)
  • .insertAt(index, value)
  • .removeAt(index)
  • .clear()

操作符

  • [index]
  • v1 + v2:连接两个Vector,返回包含所有元素的Vector
  • v1 += e1:向Vector尾部添加元素

注意

参数传递Vector对象

1
2
3
4
5
6
7
8
9
void print_vector(Vector<int> & vec){
cout << "[";
for (int i=0; i<vec.size(); i++){
if (i>0)
count << ",";
count << vec[i];
}
count << "]" << endl;
}

二维结构

1
2
Vector< Vector<int> > sodok(9, Vector<int>(9))
// 内部`Vector<int>`两侧需要空格,否则`>>`被错误解析

Stack

API

构造函数

  • Stack<type>()

方法

  • .size()
  • .isEmpty()
  • .push(value)
  • .pop()
  • .peek():返回栈顶元素但不出栈
  • .clear()

Queue

API

构造函数

  • Queue<type>()

方法

  • .size()
  • .isEmpty()
  • .enqueue(value):将值添加到队尾
  • .dequeue():删除队首元素,并返回给调用者
  • .peek():返回队首元素但不将其熟队列中删除
  • .clear()

Map

API

构造函数

  • Map<key_type, value_type>()

方法

  • .size()
  • .isEmpty()
  • .put(key, value)
  • .get(key):返回Map对象中当前与键key相关联的值
    • 若该键没有定义,get创建新的键值对,设置值为默认值
  • .remove(key)
  • .containsKey(key)
  • .clear()

操作符

  • map[key]:同get方法

Set

API

构造函数

  • Set<type>()

方法

  • .size()
  • .isEmpty()
  • .add(value)
  • .remove(value)
  • .contains(value)
  • .clear()
  • .isSubsetof(set)
  • .first()

操作符

  • s1 + s2:返回两集合并运算结果
  • s1 * s2:交
  • s1 - s2:差
  • s1 += s2
  • s1 -= s2
  • s1 *= s2

C++函数式编程

<functional>

基类

  • binary_function<arg_type1, arg_type2, result_type>: 两个指定类型参数、返回指定类型的函数类的父类
  • unary_function<arg_type, result_type>:指定类型参数、 返回指定类型的函数类的父类

实现算数操作符类

  • plus<arg_type>+
  • minus<arg_type>-
  • multiples<arg_type>*
  • divides<arg_type>/
  • modulus<arg_type>%
  • negate<arg_type>-取反

实现比较操作

  • equal_to<arg_type>==
  • not_equal_to<arg_type>!=
  • less<arg_type><
  • less_equal<arg_type><=
  • greater<arg_type>>
  • greater_equal<arg_type>>=

实现逻辑关系

  • logical_and<arg_type>&&
  • logical_or<arg_type>||
  • logical_not<arg_type>!

产生函数对象

  • bind1st(fn, value):返回新一元函数对象,用与其绑定的 value作为首个参数调用二元函数对象fn
  • bind2nd(fn, value):返回新一元函数对象,用与其绑定的 value作为第二个参数调用二元函数对象fn
  • not1(fn):返回新函数对象,且该函数对象为一元函数对象 时返回true
  • not2(fn):返回新函数对象,且该函数对象为二元函数对象 时返回true
  • ptr_fun(fnptr):返回需要调用特定函数指针的新函数对象, 可能需要一个或两个同类型参数
    • 返回具有相同效果的函数对象,可以使得函数指针、 函数对象概念一体化,避免代码重复

1
2
3
4
5
6
7
8
count_if(v.begin(), v.end(), bind2nd(less<int>(), 0));
// 返回元素类型为整形的矢量对象`v`中负数数量
template<typename FunctionClass>
void func_func(FunctionClass fn);
void func_func(double (*fn)(double)){
// 函数重载+`ptr_fun`减少代码重复
func_func(ptr_func(fn));
}

STL String

字符串:理论上是指特定字符序列

  • 声明string类型变量时,一般赋予字符串字面值作为初始值
  • 字符串长短、索引类型默认是size_t类型,在<string>类库 中已经定义

<string>

操作

  • +
  • +=
  • ==
  • !=
  • <
  • <=
  • >
  • >=

读字符串内容

  • .length()
  • .at(k):返回值可以用于赋值
  • .substr(pos, n)
  • .compare(str)
  • .find(pattern, pos)

修改接收方字符串内容

  • .erase(pos, n)
  • .insert(pos, str)
  • .replace(pos, n, str)

C风格

  • string(carray)
  • string(n, ch)
  • .c_str()