大家都知道 C++ 语言是兼容 C 语言的,所以在 C++ 中我们有最起码两种方式来实现输入输出。但是这里我还是想将这二者区分开来。毕竟目前还是喜欢在纯C的环境下面编程。所以这里就稍微介绍一下 C/C++ 里面常用的输入输出。
输入的过程
在C家族语言的编程中,我们经常需要在键盘上输入一些字符给程序。比如我们要输入 “How are you?\n”,在我们输入上面的字符后敲击回车 “\n”,此时这串字符串会先被送到一个叫输入缓冲区(一般叫 stdin )的地方,然后程序再从输入缓冲区中获取这些字符。而并不是先接受 “How”,然后接受 “are”,最后再接受 “you?\n”,很简单的反例就是当我们在输入时发现输入了我们并不想输入的字符时,我们用 可以取消之前的输入,如果不是采用输入缓冲区的机制,那么就会产生误解。
除了了解输入缓冲区的概念外,还要知道输入缓冲区指针,一个只能前进不能后退的指针,它用来标注程序目前读到缓冲区什么位置。而对于不同的输入函数,我们要注意两点,第一点是它怎样区分多个输入值,或者说缓冲区指针会吸收掉哪些分隔符;第二点是它接受输入成功后的返回值。
C里的输入
scanf
这是最常用的一种输入,无论整数还是字符串等都能够完美解决,其返回值为成功赋值的数据项数。当遇到文件结束符时返回 0。它区分多个输入值的分隔符为空格,制表符和回车。gets
gets 是从标准输入缓冲区上读字符串。可以无限读取,不会判断上限,以回车结束读取。如果读取溢出时,多出来的字符将会被写入到堆栈中,这就覆盖了堆栈原来的内容,破坏一个或多个不相关变量的值。这个导致 gets 函数已经被 gcc 摒弃,所以用 fgets 来取代 gets 。fgets
能够从 stream 中读取数据,每次读取一行。读取的数据保存在buf指向的字符数组中,每次最多读取 bufsize-1 个字符(第 bufsize 个字符赋值 ‘\0’),如果文件中该行不足 bufsize 个字符,则读完该行就结束。此时特别注意,fgets 不会像 gets 将’\n’替换成’\0’,而是在’\n’后面添加’\0’。函数成功将返回 buf 地址,失败或读到文件结尾将返回 NULL ,所以不能通过 fgets 的返回值来判断函数是否出错而终止,应该借助 feof 函数或者 ferror 函数来判断。
1#include<stdio.h>
2
3#define LEN 10
4
5int main(){
6 int a,b;
7 char str[LEN];
8
9 printf("%d\n",scanf("%d %d",&a,&b));
10 /* fflush(stdin); */
11 getchar();
12 printf("%s\n",fgets(str,LEN,stdin));
13
14 return 0;
15}
通过下图中几个测试样例可以看出 fgets 以上的特点。
C++中的输入
- cin
cin 是标准输入 istream 的一个对象,常用的方法” cin»x “,是将输入缓冲区中对象赋给x对象。其返回值根据 “»” 输入操作符的定义知道是返回 cin 对象。 cin 会吸收的分隔符有空格,制表符和回车符。
1#include<iostream>
2
3using namespace std;
4
5int main(){
6 int i;
7
8 cout<<(cin>>i)<<endl;
9
10 return 0;
11}
在多次执行该代码,发现当正确输入一个整数(90)时,返回"ox601090”,当输入错误(字符k)时,返回 0。而且在输入 90前敲了空格,制表符,回车发现cin都没有执行,所以它会吃掉那些分隔符。具体见下图:
cin.get()/cin.get(char)
用于读入一个字符,字符中包括空格,制表符,回车等。常用的方法是while((c=cin.get())!=EOF){}
或while(cin.get(c)){}
。其中 EOF 代表文件终止符,在终端中用 <ctrl+Z> 终止。cin.get(str,len,'\n’)/cin.getline(str,len,'\n’)
用于读取一串字符,其中 str 代表字符串存储的地址,len 代表最多读取 len-1 个字符,'\n’代表终止符,即碰到’\n’也停止读取。 二者也是有区别的,区别就是 getline 遇到终止字符时结束,会将缓冲区指针移动到终止字符之后,而 get 遇到终止字符时,缓冲区指针不会动。也就是说getline会吃掉终止符号。验证代码 input.cpp执行的结果如下图所示:
有两个注意点:- 代码中用 cin.get() 吃掉了4后面的换行符。
- 在 getline 中遇到’e’终止并吃掉了’e’,所以第二次输出时输出的是 “ll\nmm”,而 get 中遇到了’e’终止,却无法吃掉’e’,导致再进行 cin.get(str,10,‘e’) 时无法获取字符就又终止了。
问题&回答
- Q:根据"»"输入操作符的定义知道返回值是cin对象,所以才可以使用像"cin»a»b;“这样的连续输入,但是像"while(cin»x){}“这样的用法意味着cin»x会返回0,为什么?
A: 参见 cin的返回值探究。