用来读取命令行输入的几个函数与区别
cin
cin
是如何确定已完成字符串输入的呢?我们知道,不能通过键盘输入空字符。因此cin
使用空白(空格、制表符和换行符)来确定字符串结束的位置。cin
会忽略空格和换行符,制表符。
同时发送给cin
的输入将被缓冲,这意味着只有用户在按下回车键之后,缓冲区的内容才会发送给程序。
每次读取一行的字符串输入
istream
中的类如cin
提供了一些面向行的类成员函数:getline()
和get
这两个函数都读取一行的输入,直到到达换行符,它们的区别是,getline()
会将换行符丢弃,而get()
会将换行符保留在输入队列中。
istream::getline()
//函数原型
istream& getline (char* s, streamsize n ); //原型1
istream& getline (char* s, streamsize n, char delim ); //原型2
getline()
函数读取整行,通过回车键输入的换行符来确定输入结尾。要调用这种方法,可使用cin.getline()
。该函数原型1有两个接受两个参数。第一个参数用来接受存储 输入行的数组名称,第二个参数是要读取的字符数n
。该函数最多接受n-1
个字符,剩余位置用来存储'\0'
。注意这里接受的参数类型是char*
。
char name[10];
cout<<"Enter your name:";
cin.getline(name,10);
//用户输入"jack",然后按下回车。
cin.getline()
读取用户输入和键入Enter键生成的换行符,并将换行符替换为'\0'
。
istream::get()
cplusplus.com
int get();
istream& get (char& c);
istream& get (char* s, streamsize n); //常用
istream& get (char* s, streamsize n, char delim);//边界字符
istream& get (streambuf& sb);
istream& get (streambuf& sb, char delim);
由函数原型知道,该函数有很多变体。我们在这里只讨论和istream::getline()
工作方式类似的一种。他们接受的参数相同,且都是读取到行尾。get()
不丢弃换行符,而是将其留在输入队列中。这会导致一下问题的产生:
char name[10];
char address[20];
cin.get(name,10);
cin.get(address,10); //此处会产生问题
第一此调用函数产生的换行符会保留在输入队列中,一次第二次调用接受的第一个字符就是换行符,此时该函数认为已经到达行尾,发现没有任何需要读取的内容。这时注意到上述原型第一个不接受任何参数的get()
,它可读取下一个字符(即使是换行符)。因此可用它来处理换行符。即:
char name[10];
char address[20];
cin.get(name,10);
cin.get(); //读取换行符
cin.get(address,10);
或者
cin.get(name,10).get();
之所以这样做,是因为该函数调用会返回一个cin
对象,可以继续调用istream::get()
函数。类似的istream::getlin()
函数也一样,具体可见函数原型。
可以用istream::get()
判断停止读取的原因是什么。如果是换行符,则说明读取了整行,否则后续还有输入。
需要注意的问题
- 用
istream::getline()
或者istream::get()
读取空行会发生什么?
当istream::get()
读取空行后将设置failbit
使接下来的输入被阻断,可用cin.clear()
来恢复。 - 当输入的字符串比分配的空间长时
istream::get()
和istream::getline()
会将余下的字符留在输入队列中,而且istream::getline()
还会设置失效位failbit
并关闭后面的输入。 - 混合输入字符串和数字
混合输入字符串和数字可能会产生问题
int num;
cin>>num;
char str[80];
cin.getline(str,80);
在种种情况下,用户会没有输入str的机会,因为cin
读取年份生成的换行符留在输入队列中。此时后面的cin.getline()
看到换行符后,认为是一个空行,并将一个空字符赋给str
数组。解决的方法是在cin>>num
之后加入cin.get()
。即
int num;
cin>>num;
cin.get();
char str[80];
cin.getline(str,80);
int num;
(cin>>num).get();
char str[80];
cin.getline(str,80);
string
类I/O
可以使用cin
和运算符>>
来将输入对象存储到string
对象中,使用cout
和运算符<<
显示。但当每次读取一行而不是一个单词时,string
类的处理方法稍有不同。
string str;
getline(cin,str);
这里的getline()
不是类方法,它将cin
作为参数,指出到哪里去寻找输入,此外string
对象会根据字符串大小自动调整自己的大小。
讨论循环和文本输入
cin
对象支持3种不同模式的单字符输入,其用户接口各不相。
- 使用原始的
cin
进行输入
通常使用哨兵字符(sentinel character),缺点不能将空白字符读入(空白字符就是isspace()
返回true
的对象。
#include<iostream>
int main()
{
using namespace std;
char ch;
int count = 0;
cout<<"输入字符,按#结束\n";
cin>>ch;
while(ch!='#')
{
cout<<ch;
++count;
cin>>ch;
}
cout<<endl<<count<<" 字符被读取\n";
return 0;
}
程序会忽略空白字符。
- 使用
cin.get()
#include<iostream>
int main()
{
using namespace std;
char ch;
int count = 0;
cout<<"输入字符,按#结束\n";
cin.get(ch);
while(ch!='#')
{
cout<<ch;
++count;
cin.get(ch);
}
cout<<endl<<count<<"个字符被读取\n";
return 0;
}
cin.get()
会读取空白字符,输入仍然被缓冲。
- 文件尾条件
EOF