C/C++基础知识(一)输入输出函数之前的区别

主要是网上一些帖子的整理与自己做题的感触。

<1>主要的输入函数

1、cin

2、cin.get()

3、cin.getline()

4、getline()

5、gets()

6、getchar()

7、scanf()

<2>下面详细介绍

ps:cin.ignore();cin.get()//跳过一个字符,例如不想要的回车,空格等字符

1 cin>>

程序的输入都建有一个缓冲区,即输入缓冲区。一次输入过程是这样的,当一次键盘输入结束时会将输入的数据存入输入缓冲区,而cin函数直接从输入缓冲区中取数据。正因为cin函数是直接从缓冲区取数据的,所以有时候当缓冲区中有残留数据时,cin函数会直接取得这些残留数据而不会请求键盘输入,这就是例子中为什么会出现输入语句失效的原因!

cin提供了很多可用的成员函数和重载的操作符,如:cin<<, cin.get(), cin.getline()等。

用法1:最基本,也是最常用的用法,输入一个数字:

#include <iostream>

using namespace std;

main ()

{

int a,b;

cin>>a>>b;

cout<<a+b<<endl;

}

输入:2[回车]3[回车]

输出:5

注意:>> 是会过滤掉不可见字符(如 空格 回车,TAB 等)

cin>>noskipws>>input[j];//不想略过空白字符,那就使用 noskipws 流控制

用法2:接受一个字符串,遇“空格”、“TAB”、“回车”都结束

#include <iostream>

using namespace std;

main () {

char a[20];

cin>>a;

cout<<a<<endl;

}

输入:jkljkljkl

输出:jkljkljkl

输入:jkljkl jkljkl //遇空格结束

输出:jkljkl

2 cin.get() 可以接受空格

该函数有三种格式:无参,一参数,二参数

即cin.get(), cin.get(char ch), cin.get(array_name, Arsize)

读取字符的情况:

输入结束条件:Enter键

对结束符处理:不丢弃缓冲区中的Enter

cin.get() 与 cin.get(char ch)用于读取字符,他们的使用是相似的,

即:ch=cin.get() 与 cin.get(ch)是等价的。

读取字符串的情况:

cin.get(array_name, Arsize)是用来读取字符串的,可以接受空格字符,遇到Enter结束输入,按照长度(Arsize)读取字符, 会丢弃最后的Enter字符。

1.用法1: cin.get(字符变量名)可以用来接收字符

#include <iostream>

using namespace std;

int main (){

char ch;

ch=cin.get(); //或者cin.get(ch);

cout<<ch<<endl;

}

输入:jljkljkl

输出:j

2.用法2:cin.get(字符数组名,接收字符数目)用来接收一行字符串,可以接收空格

#include <iostream>

using namespace std;

main () {

char a[20];

cin.get(a,20);

cout<<a<<endl;

}

输入:jkl jkl jkl

输出:jkl jkl jkl

输入:abcdeabcdeabcdeabcdeabcde (输入25个字符)

输出:abcdeabcdeabcdeabcd (接收19个字符+1个'\0')

若输入超长,则按需要的长度取数据。

#include <iostream>

using namespace std;

int main (){

char ch, a[20];

cin.get(a, 5);

cin>>ch;

cout<<a<<endl;

cout<<(int)ch<<endl;

return 0;

}

测试一输入:

12345[Enter]

输出:

1234

53

【分析】第一次输入超长,字符串按长度取了"1234",而'5'仍残留在缓冲区中,所以第二次输入字符没有从键盘读入,而是直接取了'5',所以打印的ASCII值是53('5'的ASCII值)。

3.用法3:cin.get(无参数)没有参数主要是用于舍弃输入流中的不需要的字符,或者舍弃回车,弥补cin.get(字符数组名,接收字符数目)的不足.

3 cin.getline() // 接受一个字符串,可以接收空格并输出

#include <iostream>

using namespace std;

main ()

{

char m[20];

cin.getline(m,5);

cout<<m<<endl;

}

输入:jkljkljkl

输出:jklj

接受5个字符到m中,其中最后一个为'\0',所以只看到4个字符输出;

如果把5改成20:

输入:jklf fjlsjf fjsdklf

输出:jklf fjlsjf fjsdklf

//延伸:

1.cin.getline()实际上有三个参数,cin.getline(接受字符串的看哦那间m,接受个数5,结束字符)

当第三个参数省略时,系统默认为'\0'

当用在多维数组中的时候,也可以用cin.getline(m[i],20)之类的用法:

#include<iostream>

#include<string>

using namespace std;

main () {

char m[3][20];

for(int i=0;i<3;i++)

{

cout<<"\n请输入第"<<i+1<<"个字符串:"<<endl;

cin.getline(m[i],20);

}

cout<<endl;

for(int j=0;j<3;j++)

cout<<"输出m["<<j<<"]的值:"<<m[j]<<endl;

}

请输入第1个字符串:

kskr1

请输入第2个字符串:

kskr2

输入第3个字符串:

kskr3

输出m[0]的值:kskr1

输出m[1]的值:kskr2

输出m[2]的值:kskr3

2.cin.getline() 与 cin.get(array_name, Arsize)的读取方式差不多,以Enter结束,可以接受空格字符。按照长度(Arsize)读取字符, 会丢弃最后的Enter字符。

但是这两个函数是有区别的:

cin.get(array_name, Arsize)当输入的字符串超长时,不会引起cin函数的错误,后面的cin操作会继续执行,只是直接从缓冲区中取数据。但是cin.getline()当输入超长时,会引起cin函数的错误,后面的cin操作将不再执行。

#include <iostream>

using namespace std;

int main ()

{

char ch, a[20];

cin.getline(a, 5);

cin>>ch;

cout<<a<<endl;

cout<<(int)ch<<endl;

return 0;

}

测试输入:

12345[Enter]

输出:

1234

-52

【分析】与cin.get(array_name, Arsize)的例程比较会发现,这里的ch并没有读取缓冲区中的5,而是返回了-52,这里其实cin>>ch语句没有执行,是因为cin出错了!

4 getline(cin,line);

将输入流的一行数据输入到字符串变量line中。(即从输入流接收字符串,可接受空格)

getline不是C库函数,而是gcc的扩展定义或者C++库函数。它会生成一个包含一串从输入流读入的字符的字符串,直到以下情况发生会导致生成的此字符串结束:

1)到文件结束,2)遇到函数的定界符,3)输入达到最大限度。

1.C 有 fgets(), gets() 函数,gcc编译器扩展定义了getline()函数.用于读取一行字符直到换行符,包括换行符

#define _GNU_SOURCE

#include <stdio.h>

将字符串存入string时需包含#include<string>

函数声明:

ssize_t getline(char **lineptr, size_t *n, FILE *stream);

成功:返回读取的字节数。

失败:返回-1。

参数:

lineptr:指向存放该行字符的指针,如果是NULL,则有系统帮助malloc,请在使用完成后free释放。

n:如果是由系统malloc的指针,请填0

stream:文件描述符

示例:

char * line = NULL;

  size_t len = 0;

  ssize_t read;

fp = fopen("/etc/motd", "r");

  if (fp == NULL)

  exit(EXIT_FAILURE);

while ((read = getline(&line, &len, fp)) != -1){

  printf("Retrieved line of length %zu :\n", read);

  printf("%s", line);

  }

2.C++特性

char c[10]={'\0'};

cin.getline(c,10,'#');//将getline换成get试试,情况就大不相同了

PS:getline函数和cin.getline()类似,但是cin.getline()属于istream流,而getline()属于string流,是不一样的两个函数

例如下面的程序,输入是什么输出也是什么:

#include<iostream>

#include<string>

using namespace std;

main ()

{

string str;

getline(cin,str);

cout<<str<<endl;

}

输入:jkljkljkl

输出:jkljkljkl

3.getline(char*array,int count,char delim)与get(char*array,int count,char delim)的不同点:

1.当输入的字符数小于count时遇到字符delim,get函数不会读取delim这个字符,而getline函数将读取这个字符但是不存进array当中去,而是将其丢弃,当然,两者都会在读取的字符串后面自动加上'\0'(teminator character)

2.当输入的字符数大于count时,则get函数只读取count-1个字符,而其余的字符仍然保存在缓冲区中,还可再对其进行读取;但是函数getline则不然。

如果输入行包含的字符数比指定要读取的字符多,那么get()和getline()读取指定数目的字符后,将把余下的字符留在输入队列中。对get()而言,我们可以用另一条读取函数来读取留在输入队列中的数据,你也可以写一段代码将余下的字符清除。不同的是getline()会设置失效位(faibit),并且关闭后面的输入,这个时候用ch=cin.get();是读取不到留在输入队列中的字符的。你可以用下面的命令来恢复输入:

cin.clear();

因为clear()会重置失效位,打开输入。这个时候ch=cin.get();就可以读取留在输入队列中的字符。

4.ignore用法举例一则:

cin.ignore( 5, 'c' );//忽略前5个字符除非遇到字符'c',而停止忽略字符

//ignore的函数原型为:basic_istream& ignore(streamsize _Count = 1,int_type _Delim = traits_type::eof( ));

cin >> chararray;

5 scanf使用

scanf()函数取数据是遇到回车、空格、TAB就会停止

#include <stdio.h>

int main()

{

 char str1[20], str2[20];

 scanf("%s",str1);

 printf("%s\n",str1);

 scanf("%s",str2);

 printf("%s\n",str2);

 return 0;

}

如例上面的例子,第一个scanf()会取出"Hello",而"world!"还在缓冲区中,这样第二个scanf会直接取出这些数据,而不会等待从终端输入。所以测试结果如下

测试一输入:

Hello world!

输出:

Hello

world!

为了避免出现上述问题,必须要清空缓冲区的残留数据,可以用以下的方法解决:

方法1:C语言里提供了函数清空缓冲区,只要在读数据之前先清空缓冲区就没问题了!

这个函数是fflush(stdin)。

方法2:自己取出缓冲区里的残留数据。

scanf("%[^\n]",string);

PS:scanf与cin及相应输出的区别

1.scanf不安全,因为输入已经溢出,但是还能够给出正确结果且没有提示。而cout,cin会给出结果

2.cin慢是有原因的,其实默认的时候,cin与stdin总是保持同步的,也就是说这两种方法可以混用,而不必担心文件指针混乱,同时cout和stdout也一样,两者混用不会输出顺序错乱。

详细原因

scanf是格式化输入,printf是格式化输出。格式化输出效率比较高,但是写代码麻烦。

因为scanf是用指针操作的,没有类型安全机制,比如一个char类型数据你就可以用%f获得输入,而不会报错,但在运行时会出现异常。

cin是输入流,cout是输出流。效率稍低,但书写简便。流输出操作效率稍低,但书写简便。

先把要输出的东西存入缓冲区,再输出,导致效率降低,cin是自动判断你的变量类型,比如一个char数据只能用默认的char方法取数据。

3.一次输入过程是这样的:当一次键盘输入结束时会将输入的数据存入输入缓冲区,而cin函数直接从输入缓冲区中取数据。

10恰好是回车符,这是因为scanf()和getchar()函数是从输入流缓冲区中读取值的,而并非从键盘(也就是终端)缓冲区读取。而读取时遇到回车(\n)而结束的,这个\n会一起读入输入流缓冲区的,所以第一次接受输入时取走字符后会留下字符\n,这样第二次的读入函数直接从缓冲区中把\n取走了,显然读取成功了,所以不会再从终端读取!这就是为什么这个程序只执行了一次输入操作就结束的原因!

4.理论上来说cout,cin要比scanf等要慢,不过在最新的G++中,据说cin已经比scanf快了,ACM如果scanf超时的话可以用G++提交一下

刷acm的话最好使用scanf等函数,或者输出时尽量使用cout,输入时尽量使用scanf

6 getchar函数,输入单个字符

char c;

c=getch();

putchar(c);

注意连续两个getchar函数之间需要加fflush来将缓存中的换行给清除,不然会出错,如

ch1 = getchar();

fflush(stdin);

ch2 = getchar();

7 fflush(stdout);//强制刷新缓存,输出显示

fflush()会强迫将缓冲区内的数据写回参数stream 指定的文件中. 如果参数stream 为NULL,fflush()会将所有打开的文件数据更新

fflush用于清空缓冲流,虽然一般感觉不到,但是默认printf是缓冲输出的。

fflush(stdout),使stdout清空,就会立刻输出所有在缓冲区的内容。

fflush(stdout)这个例子可能不太明显,但对stdin很明显。

如下语句:

int a,c;

scanf("%d",&a);

getchar();

输入:

12(回车)

那么 a=12 ,c= '\n'

而:

int a,c;

scanf("%d",&a);

fflush(stdin);

getchar();

输入:

12(回车)

那么a=12, c暂时未得到输入值,还需要再输入c,因为getchar也是缓冲输入,'\n'本还在缓冲区,但是被清空了。

另外fflush不能作用于重定向输入流。

     

猜你喜欢

转载自blog.csdn.net/u011795345/article/details/81612734