接下来讨论的是如何给程序提供数据

cin对象将标准输入表示为字节流

通常情况下是通过键盘来生成这种字节流

cin对象根据接收值得变量类型,使用其方法将字符序列转换为所需的类型。

cin>>value_holder;

cin解释输入的方式取决于value_holder的数据类型;value_holder为存储输入的内存单元;

istream类重载了抽取运算符>>,使之能够识别下面这些基本类型;

signed char &; unsigned char &;

char &; short &; ...

典型的运算符函数的原型如下:

istream & operator>>(int &);

参数和返回值都是引用。引用参数意味着下面这样的语句将导致operator>>()函数处理变量staff_size本身,而不是像常规参数那样处理它的副本;

cin >> staff_size;

每个抽取运算符都返回调用对象的引用,这使得能够将输入拼接起来,就像拼接输出那样:

char name[20];

float fee;

int group;

cin>>name>>fee>>group;

=====================================================

一、cin>>如何检查输入

不同版本的抽取运算符查看输入流的方法是相同的。

它们跳过空白,直到遇到非空白字符。

空白字符(空格、换行符、制表符);

例如对于下面的代码:

int elevation;

cin >>elevation;

假设输入下面的字符:

-123Z

运算符将读取字符 - 、1、2和3;因为它们都是整数的有效部分;但Z不是有效字符。

因此输入中最后一个可接受的字符是3。Z将留在输入流中。下一个cin语句将从这里开始读取。

与此同时,运算符将字符序列-123转换为一个整数值,并将它赋给elevation。

输入有时候并不能满足要求,例如输入的是Zcar,而不是-123Z。在这种情况下,抽取运算符将不会修改elevation的值,并返回0;

返回值false让程序能够检查输入是否满足要求。

//check_it.cpp  -- checking for valid input
#include<iostream> int main()
{
using namespace std;
cout<<"Enter numbers: "; int sum = ;
int input; while(cin>>input)
{
sum += input;
} cout<<"Last value entered = "<<input<<endl;
cout<<"Sum = "<< sum <<endl;
return ;
}

运行结果

Enter numbers: 200
10 -50 -123Z 60
Last value entered = -123
Sum = 37

分析

由于输入是被缓冲的,因此通过键盘输入的第二行在用户按下回车键之前,是不会被发送给程序的。

然而,循环在字符Z处停止了对输入的处理,因此它不与任何一种浮点格式匹配。

输入与预期不匹配反过来讲导致表达式cin>>input的结果为false,因此while循环被终止。

=====================================================

二、流状态

接下来进一步讨论不适当的输入会带来什么后果;

cin或cout对象包含一个描述流状态(stream state)的数据成员。

流状态有3个ios_base元素组成:eofbit、badbit、failbit;

流状态被定义为iostate类型,是一种bitmask类型;

当全部3种状态被设置为0时,说明一切顺利;

当cin操作到达文件末尾时,它将设置eofbit;

当cin操作未能读到预期的字符时,它将设置为failbit;

在一些无法诊断的失败破坏流时,badbit元素将被设置failbit;

1、设置状态

下面介绍两种方法——clear()setstate()很相似;

clear();               //这样的调用将使用默认参数0,这将清除全部3个状态位(eofbit、badbit、failbit);

clear(eofbit);      //这将会设置eofbit位,同时另外两个状态位被清除;

setstate()方法只影响其参数中已被设置的位。

setstate(eofbit)   //只会影响eofbit,而不会影响其他位;

为什么需要重新设置位状态?

  这取决于程序需要执行的任务;

2、I/O和异常

cin.exceptions(badbit);  //如果badbit位被设置,将引发异常;

cin.exceptions(badbit|eofbit);  //如果badbit或eofbit被设置,将引发异常;

下面的程序,能够在failbit被设置时引发并捕获异常;

 //cinexcp.cpp  -- having cin throw an exception
#include<iostream>
#include<exception> int main()
{
using namespace std;
cin.exceptions(ios_base::failbit);
cout<<"Enter numbers: "; int sum = ;
int input;
try{
while(cin>>input)
{
sum += inputs;
}
}catch(ios_base::failure & bf)
{
cout<<bf.what()<<endl;
cout<<"O! the error!\n":
} cout<<"Last value entered = "<<input<<endl;
cout<<"Sum = "<< sum <<endl;
return ;
}

运行结果

Enter numbers: 20 30 40 pi 6

ios_base failure in clear

O! the horror!

Last value entered = 40.00

Sum = 90.00

3、流状态的影响

设置流状态可以有非常重要的后果:流将对后面的输入或输出关闭,直到位被清除;

如果希望程序在流状态位被设置后能够读取后面的输入,就必须将流状态重置为良好。

这可以通过调用clear()方法来实现;

while(cin>>input)

{

  sum += input;

}

cout<<"Last value entered = "<<input<<endl;

cout<<" Sum = "<<sum<<endl;

cout<<"Now enter a new number: ";

cin.clear();  //reset stream state

while(!isspace(cin.get()))

  continue;

cin>>input;   //will work now

注意这还不足以重新设置流状态。导致输入循环终止的不匹配输入仍留在输入队列中,程序必须跳过它。

一种方法是一直读取字符,直到到达空白为止;

isspace()函数是一个cctype函数,它在参数是空白字符时返回true。

另一种方法是丢弃行中的剩余部分,

while(cin.get() != '\n')

  continue;  //get rid rest of line

现在假设循环是由于到达文件尾或者由于硬件故障而终止的。

可以使用fail()方法检测假设是否正确,来修复问题。

fail()在failbit或eofbit被设置时返回true。因此代码必须排除这种情况;

while(cin>>input)

{

  sum += input;

}

cout<<"Last value entered = "<<input<<endl;

cout<<" Sum = "<<sum<<endl;

if(cin.fail() && !cin.eof())

{

}

else  //else bail out

{

  cout<<"I cannot go on!\n";

  exit(1);

}

cout<<"Now enter a new number:";

cin>>input;   //will work now

=====================================================

三、其他istream类方法

非格式化输入函数,因为它们只是读取字符输入,而不会跳过空白,也不进行数据转换;

  函数get(char*, int, char)getline(char*, int, char)在默认情况下读取整行而不是一个单词;

  方法get(char &)get(void)提供不跳过空白的单字符输入功能

1、单字输入

在使用char参数或没有参数的情况下,get()方法读取下一个输入字符,即使该字符是空格、制表符或换行符;

get(char & ch)版本将输入字符赋给其参数。

而get(void)版本将输入字符转换为整型(通常是int),并将其返回。

1)成员函数get(char &)

int ct = 0;

char ch;

cin.get(ch);

while(ch != '\n')

{

  cout<<ch;

  ct++;

  cin.get(ch);

}

cout<<ct<<endl;

假设输入了 I C++ clearly.<Enter>

输出的结果是 I C++ clearly.

假设程序试图使用>>
int ct = 0;

char ch;

cin>>ch;

while(ch != '\n')

{

  cout<<ch;

  ct++;

  cin>>ch;

}

cout<<ct<<endl;

则代码首先跳过空格,这样做将不考虑空格。因此相应的输出压缩为:

IC++clearly.

这里有个很糟糕的情况,抽取运算符跳过了换行符,因此代码不会将换行符赋给ch,所以while循环测试将不会终止;

get(char &)成员函数返回一个指向用于调用它的istream对象的引用,这意味着可以拼接get(char &)后面的其他抽取:

char c1,c2,c3;

cin.get(c1).get(c2)>>c3;

首先cin.get(c1)将第一个输入字符赋给c1,并返回调用对象——cin.

这样代码缩为cin.get(c2)>>c3,它将第二个输入字符赋给c2.该函数调用返回cin,将代码缩为cin>>c3。

这将把下一个非空白字符赋给c3。因此c1和c2的值最后为空格,但c3不是。

如果cin.get(char &)到达文件尾——无论是真正的文件尾还是模拟尾。它都不会给参数赋值了。也就是说到达文件尾时,没有值可以赋给参数了。

char ch;

while(cin.get(ch))

{

  //process input

}

只要存在有效输入,cin.get(ch)的返回值都是cin,此时判定结果为true,因此循环将继续。

到达文件尾时,返回值判定为true,循环终止。

2) 成员函数get(void) 

get(void)使用返回值的形式来将输入传递给程序。

可以这样使用它:

int ct = 0;

char ch;

ch = cin.get();

while(ch != '\n')

{

  cout<<ch;

  ct++;

  ch = cin.get();

}

cout<<ct<<endl;

get(void)成员函数的返回类型为int,这使得下面的代码是非法的:

char c1, c2, c3;

cin.get().get()>>c3; //not valid

到达文件尾后,cin.get(void)都将返回值EOF——头文件提供的iostream提供的一个符号常量。

int ch;

while((ch = cin.get()) != EOF)

{

  //process input

}

2、采用哪种单字输入形式

假设可以选择>>、get(char &)、get(void),应该使用哪一种呢?

首先应该确定是否希望跳过空白。

如果跳过空白更加方便,则使用抽取运算符>>;

如果希望程序检查每个字符,请使用get()方法。

3、字符串输入:getline()、get()和ignore()

istream & get(char *, int, char);

istream & get(char *, int);

istream & getline(char *, int, char);

istream & getline(char *, int);

  第一个参数哟用于防止输入字符串的内存单元的地址;第二个参数比要读取的最大字符数大1;第三个参数指定用作分界符的字符;

例如,下面的代码将字符输入读取到字符数组line中:

char line[50];

cin.get(line,50);

cin.get()函数在到达第49个字符或遇到换行符后停止将输入读取到数组中。

get()和getlne()的区别在于;get()将换行符留在输入流中,那么接下来的输入操作首先看到的将是换行字符。而getline()抽取并丢弃输入流中的换行符。

第三个参数的用法,遇到分界符后,输入将停止,即使还未读取到最大数目的字符。

默认情况下,get()将分界字符留在输入队列中,getline()不保留。

 //get_fun.cpp  -- using get() and getline()
#include<iostream>
const int Limit = ; int main()
{
using std::cout;
using std::cin;
using std::endl; char input[Limit];
cout<<"Enter a string for getline() processing:\n";
cin.getline(input, Limit, '#');
cout<<"Here is your input: ";
cout<<input<<"\nDone with phase 1\n"; char ch;
cin.get(ch);
cout<<"The next input character is "<<ch<<endl; if(ch != '\n')
cin.ignore(Limit, '\n'); cout<<"Enter a string for get() processing:\n";
cin.get(input, Limit, '#');
cout<<"Here is your input:\n";
cout<<input<<"\nDone whti phase 2\n"; return ;
}

运行结果:

Enter a string for getline() processing:

Please pass

me a #3 melon!

Here is your input:

Please pass

me a

Done with phase 1

The next input character is 3

Enter a string for get() processing:

I still

want my #3 melon!

Here is your input:

I still

want my

Done with phase 2

The next input character is #

其中的cin.ignore(Limit, '\n');  这个函数调用将读取并丢弃接下来的255个字符直到到达第一个换行符;

看下原型:

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

默认参数值EOF导致igonre()读取指定数目的字符或读取到文件尾。

该函数返回调用对象,这使得能够拼接函数调用;

cin.ignore(255, ‘\n’).ignore(255, '\n');

其中,第一个调用读取并丢弃一行,第二个调用读取并丢弃一行。因此一共读取了两行

4、意外字符串输入

get(char* , int)和getline()的某些输入形式将影响流状态。

这两个函数在遇到文件尾时,将设置eofbit;

遇到流破坏时,将设置badbit;

另外两种情况是,无输入以及输入到达或超过函数调用指定的最大字符数

如果不能抽取字符,它将把空值字符放置到输入字符串中,并使用setstate()设置failbit

什么时候不能抽取字符:1)输入方法到达了文件尾;2)输入了空行

输入空行并不会导致getline()设置failbit。这是因为getline()仍将抽取换行符,虽然不会存储它。

如果希望getline()在遇到空行时终止循环,可以这样编写:

char temp[30];

while(cin.getline(temp,80)  && temp[0] != '\0')  //terminate on empty line

如果输入队列中的字符数超过了输入方法中指定的最大字符数;

如果读取了最大字符数,并且下一个字符不是换行符,则设置failbit;

接下来看一下get(char * int)方法:

它首先读取字符数,然后测试是否为文件尾以及下一个字符是否是换行符

提供它读取了最大数目的字符,则不设置failbit标记;

可以用peek()查看下一个输入字符,如果是换行符,则说明已经读取了整行;如果不是换行符,则说明get()在到达行尾前停止;

getline()不适合使用peek()方法,是因为getline()读取并丢弃了换行符;

如果使用get(),则可以知道是否读取了一整行;

=====================================================

四、其他istream方法

其他istream方法还包括read()、peek()、gcount()和putback()。

read()函数读取指定数目的字节,并将它们存储在指定的位置中。

char gross[144];

cin.read(gross, 144);

这段代码从标准输入中读取144个字节,并将它们存储在gross数组中;

注意read()不会在输入后面加上空值字符,因此不能将输入转换为字符串;

read()方法不是为键盘而设计的,它与ostream write()函数配合使用,来完成文件输入和输出

该方法的返回类型为istream &,因此可以像下面这样将它拼接起来:

char gross[144];

char score[20];

cin.read(gross, 144).read(score, 20);

peek()函数返回输入中的下一个字符,但不抽取输入流中的字符。

可以用peek()查看输入流中的下一个字符,以此来判断是否继续读取:

char great_input[80];

char ch;

int i = 0;

while(ch = cin.peek() != ' . '  && ch != '\n')

  cin.get(great_input[i++]);

great_input [i] = '\0';

gcount()方法返回最后一个非格式化抽取方法读取的字符数。

这指的是有get()、getline()、ignore()、read()方法读取的;

putback()函数将一个字符插入到输入字符串中

putback()方法接受一个char参数——要插入的字符,其返回类型是istream &;这使得可以将该函数调用与其他istream方法拼接起来;

被插入的字符是下一条输入语句读取的第一个字符。

 //peeker.cpp  -- some istream methods
#include<iostream> int main()
{
using std::cout;
using std::cin;
using std::endl; //read and echo input up to a # character
char ch; while(cin.get(ch)) //terminate on EOF
{
if(ch != '#')
cout<<ch;
else
{
cin.putback(ch); //reinsert character
break;
}
} if(!cin.eof())
{
cin.get(ch);
cout<<endl<<ch<<" is next input character.\n";
}
else
{
cout<<"End of file reached.\n";
std::exit();
} while(cin.peek() != '#') // look ahead
{
cin.get(ch);
cout<<ch;
} if(!cin.eof())
{
cin.get(ch);
cout<<endl<<ch<<" is next input character.\n";
}
else
cout<<"End of file reached.\n";
return ;
}

运行结果

I used a #3 pencil when I should have used a #2.

I used a

# is next input character.

3 pencil when I should have used a

# is next input character.

 //truncate.cpp  -- using get() to truncate input line, if necessary
#include<iostream>
const int SLEN = ;
inline void eatline() {while (std::cin.get() != '\n') continue;} int main()
{
using std::cout;
using std::cin;
using std::endl; char name[SLEN];
char title[SLEN];
cout<<"Enter your name: ";
cin.get(name,SLEN); if(cin.peek() != '\n')
cout<<"Sorry, we only have enough room for "<<name<<endl;
eatline(); cout<<"Dear"<<name<<", enter your title: \n";
cin.get(title, SLEN);
if(cin.peek() != '\n')
cout<<"We were forced to truncate your title.\n";
eatline();
cout<<"Name: "<<name<<"\nTitle: "<<title<<endl; return ;
}

运行结果:
Enter your name: Ella Fishsniffer

Sorry, we only have enough room for Ella Fish

Dear Ella Fish, enter your title:

Executive Adjunct

We were forced to truncate your title.

Name: Ella Fish

Title: Executive

注意,下面的代码确定第一条输入语句是否读取了整行:

while(com.get() != '\n') continue;

C++_IO与文件3-用cin进行输入的更多相关文章

  1. C++_IO与文件4-简单文件的输入与输出

    通过键盘输入和屏幕输出被称为是控制台输入/输出: 更广义上讲控制台的输入/输出也是一种特殊的文件输入/输出: 当使用cin进行输入时,程序将输入视为一系列的字节,其中的每个字节都被解释成字符编码: 不 ...

  2. python3 下的文件输入输出特性以及如何覆盖文件内容和接下去输入

    今天碰到了一个非常有意思的python特性.本来我是想打开一个文件,在文件的末尾接下去输入一些内容的,代码如下: f = open('test.txt', 'r+') f.write(content) ...

  3. cin 字符串输入

    cin 字符串输入 在学习c的时候,关于字符串的输入,记得有 scanf("%s",s); gets(s); 还有...o.o 好想没了... scanf("%s&quo ...

  4. cin循环输入控制问题

    之前写一个简单的输入节点值自动生成链表的测试程序,发现cin的输入控制好像在VC++6.0和VS2010中不一样,特此记录. 现在有以下代码: vector<int> ivec; int ...

  5. 为什么我上传了flv或MP4文件到服务器,可输入正确地址通过http协议来访问总是出现“无法找到该页”的404错误呢

    常用MIME类型(Flv,Mp4的mime类型设置) 也许你会在纳闷,为什么我上传了flv或MP4文件到服务器,可输入正确地址通过http协议来访问总是出现“无法找到该页”的404错误呢?这就表明mp ...

  6. C语言重定向输入:txt文件内容是中文,重定向输入显示乱码的原因

    一.txt文件中的内容是中文,重定向输入显示乱码原因: 是因为文本文件的编码和和编译器的不一致导致的.我文本文件用的编码是UTF-8,而编译器是ANSI,不匹配,所以输出乱码.文本另存为时把编码改为A ...

  7. C++_IO与文件5-文件的输入与输出

    大多数计算机程序都使用了文件.文件本身是存储在某种设备上的一系列字节. 通常,操作系统管理文件,跟踪它们的位置.大小.创建时间等. 除非在操作系统级别上编程,否则通常不必担心这些事情. 真正需要的是将 ...

  8. C++_IO与文件2-用cout进行输出

    C++将输出流看作是字节流,在程序中,很多数据被组织成比字节更大的单位. 例如int类型由16位或者32位的二进制值表示:double值由64位的二进制数据表示: 但是在将字节流发送给屏幕时,希望每个 ...

  9. C++_IO与文件1-输入与输出概述

    为了方便起步先从istream类对象cin和ostream类对象cout开始,了解输入和输出的基本方法: 同时使用ifstream和ofstream对象进行文件的输入和输出: 然后详细学习cin和co ...

随机推荐

  1. 用java和汇编开发一个hello world系统内核

  2. 1-5 构建官方example-Windows平台

    https://github.com/facebook/react-native https://github.com/facebook/react-native.git  https://githu ...

  3. c之指针退化和printf小陷阱

    今天参加了个笔试和面试,面试官给我指出了我试卷上的错误,我才发现,我的知识疏漏之处原来有不少,很是感谢. 记得曾经有本书,专门写c的陷阱来着,里面有很多都牵扯到指针.嘿嘿,这小家伙古灵精怪,总是喜欢误 ...

  4. 面试题:彻底理解ThreadLocal 索引的利弊 背1

    .索引利弊   --整理 1.索引的好处 a.提高数据检索的效率,降低检索过程中必须要读取得数据量,降低数据库IO成本. b.降低数据库的排序成本.因为索引就是对字段数据进行排序后存储的,如果待排序的 ...

  5. Shell +Cygwinterminal+WinMySQL 传参数授权

    前言:新公司因为部分业务原因有好几百组win机器装MySQL授权登录比较麻烦,简单的写了一个shell传值自动授权的脚本,保存复用. #!/bin/bash #author liding@zlhy.c ...

  6. c语言学习笔记-if语句块一定要加分号

    if(a>6) printf("hello");//语句1 printf("world");//语句2 当a>6的时候,执行的分支语句是语句1,而不 ...

  7. hdu 4681 String(转载)

    #include <stdio.h> #include <string.h> #include <algorithm> #include <iostream& ...

  8. 递增三元数组——第九届蓝桥杯C语言B组(省赛)第六题

    原创 标题:递增三元组 给定三个整数数组A = [A1, A2, ... AN], B = [B1, B2, ... BN], C = [C1, C2, ... CN],请你统计有多少个三元组(i, ...

  9. 温故而知新:什么是wcf

    1.什么是WCF.WCF是Windows Communication Fundation的缩写,是微软在.net 3.0 的时候引进的,用于开发可交互的分布式应用程序,是由微软发展的一组数据通信的应用 ...

  10. Oracle下载及安装

    Oracle   下载及安装 一.官方下地址:   http://www.oracle.com/technetwork/database/enterprise-edition/downloads/in ...