C++ std::cin
C++ std::cin
相关概念
- istream 一个class,提供输入操作。
- cin 一个 istream 对象,用于从标准输入读取数据。
- >> 运算符,用于从一个 istream 对象读取输入数据。
【注】cin 中的字符 ‘c’ 指 ‘character’,“cin” 就是 ‘character input’ 的意思
std::cin 是一个全局对象,与标准C输入流 stdin 关联。
使用
1. 一个常见的使用场景:
int main() {/*...*/int ival;cin >> ival;/*...*/return 0;
}
支持多类型输入:
int main() {int iage;std::string strname;std::cout << "Enter 'name' and 'age': ";std::cin >> strname >> iage;std::cout << "Name: " << strname << "\\t" << "Age: " << iage << std::endl;return 0;
}
因为 cin 会跳过空白字符比如 空格、回车,所以虽然在同一行输入了名字和类型,但是它们会分开保存到对应的变量中:
2. 用于静态对象的构造和析构函数中,访问标准输入/输出流是安全的。
#include<iostream>
struct UserDefinedStruct{int m_ival;UserDefinedStruct() {std::cout << "Enter ival: ";std::cin >> m_ival;}
};
// 定义一个静态对象
UserDefinedStruct uds;int main() {std::cout << "uds.m_ival is "<< uds.m_ival<< std::endl;return 0;
}
3. 作为 while 语句的条件
int ival;while(cin >> ival) {/*...*/
}
cin 操作的对象是一个 int 变量,输入运算符期待读取一个 int,当输入不符合期待时(比如输入字符 ‘a’),cin 就会进入错误状态,因此跳出循环。
那么 cin >> ival 为什么可以作为 while 的条件?
查看操作符 >> 的函数定义:
basic_istream& operator>>( int& value );
也就是说,basic_istream 在特定上下文中是可以隐式转换为一个 bool 值。我们知道 IO 操作的一个问题就是它有可能会产生问题。。。因此 IO 类中定义了一些函数和标志以便于使用者访问和操纵流的条件状态,参看 C++ Primer 第五版:
cin >> ival 之所以可以作为 while 语句的条件,是因为 istream 重载了 operator bool,而 operator bool 会在 fail() 为 false 并且还处于 IO ready state 的时候返回 true。
当 cin >> ival 遇到键入的 ‘a’ 时,因为 ‘a’ 并不是理想的输入,failbit 置位,又因为是在 while 的条件中,这是一个 bool 语境,因此调用了 operator bool, 而 operator bool 中又调用了 fail(),因为 fail() 返回 true,所以 operator bool 返回 false。。。因此退出了循环(为什么不调用 good() 呢。。。)
这个转换是隐式的,咋一看会很迷惑。
前面的例子都是通过 cin 搭配操作符 << 来使用的,外部输入的数据被保存在 cin 的缓冲区中,通过操作符 “<<” 把数据从 cin 中提取出来。操作符 >> 表现为带格式的输入。
在不带格式的输入场景下,可以使用 get 或者 getline。
4. 配合 get、getline 使用
cin 和 get 或者 getline 的组合使用方式十分相似:
// 程序 1
#define MAX_LEN 20int main() {char ch[MAX_LEN];std::cout << "Enter: ";std::cin.get(ch, MAX_LEN);std::cout << "Entered: " << std::endl;// 这里用于输出计数for(int i = 0; i != 4; ++i) {for (int j = 0; j != 10; ++j) {std::cout << j;}}std::cout << '\\n';std::cout << ch;return 0;
}
输入字符串在长度限制内:
输入字符串超出长度限制:
// 程序 2
#include<iostream>int main() {char strname[32];char straddr[256];std::cout << "Enter your name: ";std::cin.getline(strname, 32);std::cout << "Enter your address: ";std::cin.getline(straddr, 256);std::cout << strname << "'s address: " << straddr << std::endl;return 0;
}
不同的是 get 每次读取一整行并把换行符留在输入队列中,因此在连续多次输入的场景下需要在每次 get 用户输入后再调用一次 get 读取换行符,或者调用 ignore 忽略换行符。而 getline 每次读取一整行后会把换行符丢弃(可以修改程序 2 中的 getline 进行测试)。