alias: [字符串读入]
tags:

  • 字符串
  • 读入
    from:

本文章讨论的都是带有输入缓冲的输入规则,此部分需要理解输入缓冲区规则
C++ 标准输入和输出,stdin、stdout 和 stderr 的缓存特征是:stdin 和 stdout 是行缓存;而 stderr 是无缓存的。cin 和 cout 都是从缓冲区读取

输入都建有一个缓冲区,即输入缓冲区。一次输入过程是这样的,当一次键盘输入结束时会将输入的数据存入输入缓冲区,而输入语句直接从输入缓冲区中取数据。正因为是直接从缓冲区取数据的,所以有时候当缓冲区中有残留数据时,输入函数会直接取得这些残留数据而不会请求键盘输入。例如当我们输入一些数据按下回车时,这些数据会被第一条输入语句读入,但有一些函数却不会把这个回车符读入并舍弃掉(比如 gets),这时第二条输入语句便会直接读取到这个回车符从而认定已经完成了输入直接跳过了输入语句。

#include <iostream>
using namespace std;
int main()
{
    char str[8];
    cin.getline(str, 5);
    cout<<str<<endl;
    cin.getline(str, 5);
    cout<<str<<endl;
    return 0;
}

分析:

abcdefgh (回车)

abcd (输出)

(输出 - 换行)

【分析】之所以第一次输入完后直接程序就结束了,而不是进行第二次输入,是因为第一次多输入的数据还残留在缓存区中,第二次输入就直接从缓存区中提取而不会请求键盘输入,以下探讨几种常见的输入方式:

读入

cin>>

该操作符是根据后面变量的类型读取数据。

输入结束条件 :遇到 Enter、Space、Tab 键。

对结束符的处理 :
>> 会跳过前置的结束符 或者说丢弃的前置缓冲区中输入结束的结束符 (Enter、Space、Tab),但是读入后字符后面的实际还在缓冲区中。

同时 cin 去除读入的前面的结束字符字符,避免 cin 接收不到

#include <iostream>
using namespace std;int main()
{
 int a,b;
 
 cin>>a>>b;
 cout<<a<<"  "<<b<<endl;
 
 return 0;
}

读入 1         3
输出 1 3
因为读入1后遇到多个空格cin 不接收而遇到3 接收

string

读入单词类字符串(不读入空格)

“I love china”

# 输出最后一个单词长度示例 ----华为机试
string s;
while(cin>>s) # 读到 回车 即结束循环
{
	pre=s;
}
cout<<pre.length()<<endl;
读入整行(包括空格),遇回车结束 getline

读取时遇到换行符结束

在默认情况下,getline() 遇到换行符使停止读入,所以必须保证在调用它之前缓冲区没有任何多余的输入。如:

string a;
string str;
cin >> a;
getline(cin, str);

输入 abc 后,换行,再想输入字符串是不行的,他会把 abc 给 a,然后 getline() 遇到换行直接就停止了。

其实就是输入 abc 后,结束字符会被 getline 读取到,例如输入 fer 空格 再输入 abc,那么 str 等于空格 +abc。
因为 cin 遇到空格后停止但是空格仍然存在,所以需要消除
第二个例子比如输入 abc 回车,那么输入就会停止因为 cin 没有消除回车

解决方法:在 cin 后面跟一个 cin.get()。

string str;
getline(cin,str);
// 遍历
for(int i=0;i<str.length();i++)

char

cin 的 get getline

cin.get(数组名,长度,结束符)

其中结束符为可选参数,读入的字符个数最多为(长度 -1)个,结束符规定结束字符串读取的字符,默认为 ENTER
若要读取字符,直接 cin.get(char ch) 或 ch=cin.get() 即可

输入结束条件:默认 Enter 键(因此可接受空格,Tab 键),可在第三个参数上自定义结束符

输入结束条件:Enter 键

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

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

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

区别

get 和 getline 区别:当遇到结束字符时,两者的处理方式不同。getline() 函数会将结束字符丢弃,不会保存在字符串里,也不会保存在输入队列里,对下一次调用 getline 或者 get 没有影响;而 get() 函数虽然同样不会将结束字符保存在字符串里,但会将它保存在输入队列里,如果后面还有一个 get 或者 getline 函数,会直接读取到结束字符然后结束。解决方法是使用一个不带任何参数的 cin.get() 调用可读取下一个字符,处理到结束字符后再正常使用其他 get 或 getline 函数。

输入队列:相当于有个队列在那里,你每输入一个字符就会进入队列,cin 等函数就是从队列里面一个一个的取数,cin 和 get 在遇到结束字符的时候,直接停止读取,不会把结束字符读进字符串,但是不会把结束字符取出来,后面的 get、getline 函数还是会读取到这个结束字符;而 getline 在遇到结束字符的时候,也不会把结束字符读进字符串,但是会把结束字符取出来丢掉,那么下一个 get、getline 之类的函数就不会再读取到这个结束字符,而是直接读取到后面的内容。比较神奇的是,如果后面跟的是 cin 并不受影响。比如连续使用 cin 时,第二个 cin 并不会受到上一个输入的结束字符的影响,因为会自动忽略空白 (空格、换行、制表符等) 并从第一个真正的字符开始读起,直到遇到下一处结束字符为止。

cin.get() / cin.getline() ----char str[]

这两个方法是给 char 使用的

char str[1005];
cin.get(str,1005);
cin.getline(str,1005); //第二个参数决定最多能读入多少个字符(包括最末尾的'\n')
// 遍历
for(int i=0;i<strlen(str);i++)  // strlen() ----> #include <cstring>

1)先来看一看利用 cin 读取字符串

cin 使用空白(空格、制表符、换行符(通过回车符输入))来确定字符串的结束位置,这意味着通过 cin 读入字符数组时只读取一个单词,空白仍保留在流中,读取该单词后,cin 将该字符串放在数组中,并自动在结尾加入空字符(‘\0’);流中单词之前的空白将被忽视,而直接保存单词;单词之后的空格仍保存在流中!

2)再看看 cin.getline(char*,int) 读取字符串

cin.getline(char_,int) 将 int-1 个字符读取到数组 char_ 中,最后一个位置用来存储 ‘\0’。该函数在读取指定数目的字符或者遇到换行符时停止读取。该函数从流中抽取出换行符,但不保存换行符。

3)再看看 cin.get(void) 读取字符串

cin.get() 往往用来从流中抽取换行符,防止下一次读入时因读入换行符而提前结束。往往和 get(a,b) 结合使用,因为 get(a,b) 不从流中抽取换行符。

4)再看看 cin.get(a) 读取字符串(一个引用类型参数)

cin.get(ch) 该读取方法可以补救 cin 读取方法的缺点,即可以将空白读入并存储,但是该方法只能一个字符一个字符读取,往往对于字符串的读取不太方便,故用的较少。

5)再看看 cin.get(char * ,int) 读取字符串(两个参数)

cin.get(char_,int) 与 cin.getline(char_,int) 函数很相似,唯一不同的地方在于:get 函数不从流中抽取换行符,换行符仍保留在流中,因为其后往往要跟 cin.get(),用来抽取换行符。

scanf

scanf 输入字符串主要针对 char 数组或者 char 指针

在 C 语言中,有两个函数可以让用户从键盘上输入字符串,它们分别是:

  • scanf():通过格式控制符 %s 输入字符串。除了字符串,scanf() 还能输入其他类型的数据。
  • gets():直接输入字符串,并且只能输入字符串。

但是,scanf() 和 gets() 是有区别的:

  • scanf() 读取字符串时以空格为分隔,遇到空格就认为当前字符串结束了,所以无法读取含有空格的字符串。
  • gets() 认为空格也是字符串的一部分,只有遇到回车键时才认为字符串输入结束,所以,不管输入了多少个空格,只要不按下回车键,对 gets() 来说就是一个完整的字符串。换句话说,gets() 用来读取一整行字符串。

scanf() 的用法还可以更加复杂和灵活,它不但可以完全替代 gets() 读取一整行字符串,而且比 gets() 的功能更加强大。比如,以下功能都是 gets() 不具备的:

  • scanf() 可以控制读取字符的数目;
  • scanf() 可以只读取指定的字符;
  • scanf() 可以不读取某些字符;
  • scanf() 可以把读取到的字符丢弃。

如果想把一个字符串读入程序,首先必须预留储存该字符串的空间,然后用输入函数获取该字符串。

分配空间

1.char *name;

2.char name[81];
1,2 的不同点:1.的指针在未进行初始化之前可能指向任何地方。
2.已分配了 81 个字节的地址。

char *name;
scanf(“%s”,name); // 错误 会将输入的字符串拷贝到任何地方可能会擦写掉程序中的数据或代码。
为字符串分配内存后便可读入字符串。

scanf

scanf 与 cin 一样

弊端:只能读取一个单词。

原理:如果输入了空格会认为字符串结束,将空格后的字符作为下一个输入处理。
例如:scanf(“%s”,name); 输入:aas df 会将 aas 放入地址中再在后面自动添加 ‘\0’,并将 df 作为下一个输入处理。

#include <stdio.h>
int main()
{
char ch1[10],ch2[10];
 
  scanf("%s",ch1);
  scanf("%s",ch2);
  printf("%s,%s",ch1,ch2);
return 0;
}

输入:ass df
输出ass,df

gets() 函数。

弊端:该函数只知道数组的开始处,并不知道数组的大小,如果输入的字符串过长容易溢出,可能擦写掉程序中的其他数据导致程序异常终止。

原理:读取整行的输入直至遇到换行符,然后丢弃换行符,储存其余字符,并在这些字符末尾添加一个空字符使其成为一个字符串。

#include <stdio.h>
int main()
{
char ch1[10],ch2[10];
 
  gets(ch1);
  gets(ch2)
  printf("%s,%s",ch1,ch2);
return 0;
}

getchar

读入一个字符与 cin.get 差不多

char c = getchar()

Scanner Java

Scanner 类各种方法的实现

Scanner sc = new Scanner(System.in)

next() 与 nextLine() 读取字符串

next():

与 cin 类似,但是会处理掉 next 结束后的换行

  1. 一定要读取到有效字符后才可以结束输入。
  2. 对输入有效字符之前遇到的空白,next() 方法会自动将其去掉。
  3. 只有输入有效字符后才将其后面输入的空白作为分隔符或者结束符。
  4. next() 不能得到带有空格的字符串。
  5. 不会处理缓冲区后面的空格

nextLine():

与 getline 类似

  1. 以 Enter 为结束符,nextLine() 方法返回的是输入回车之前的所有字符。
  2. 可以获得空白。
  3. 处理缓冲区后面的换行符
public static void main(String[] arg){  
  Scanner in1=new Scanner(System.in);   
  System.out.println("What is your name?");  
  String name1=in1.nextLine();  
  System.out.println("你的姓名是"+name1);  
    
  Scanner in2=new Scanner(System.in);   
  System.out.println("What is your name?");  
  String name2=in2.next();  
  System.out.println("你的姓名是"+name2);  
 }
结果:

What is your name?  
wan ming  
你的姓名是wan ming  
What is your name?  
wan ming  
你的姓名是wan

hasNextXxx()

判断输入的类型是否为想要的

netInt() 和 nextFloat()

读取整数和浮点数及通过 hasNextXxx 进行判断

public static void main(String[] args) {   
         Scanner scan = new Scanner(System.in);    
         int i = 0 ;   
         float f = 0.0f ;   
         System.out.print("输入整数:");   
         if(scan.hasNextInt()){                 // 判断输入的是否是整数   
             i = scan.nextInt() ;                 
             System.out.println("整数数据:" + i) ;   
         }else{                                 // 如果输入错误的信息   
             System.out.println("输入的不是整数!") ;   
         }   
         System.out.print("输入小数:");   
         if(scan.hasNextFloat()){               // 判断输入的是否是小数   
             f = scan.nextFloat() ;              
             System.out.println("小数数据:" + f) ;   
         }else{                                 //如果 输入错误的信息   
             System.out.println("输入的不是小数!") ;   
         }   
     } 

结果:

输入整数:10  
整数数据:10  
输入小数:10.0  
小数数据:10.0

nextDouble

读取浮点数及输入多个数字求总和平均数

public static void main(String[] args)   {   
        Scanner scan = new Scanner(System.in);   
        double sum = 0;   
        int m = 0;   
        while(scan.hasNextDouble())  {   
            double x = scan.nextDouble();   
            m = m + 1;   
            sum = sum + x;   
        }   
   
        System.out.println(m+"个数的和为"+sum);   
        System.out.println(m+"个数的平均值是"+(sum/m));   
    }   
结果:

10  
12  
15  
24  
25  
end  
5个数的和为86.0  
5个数的平均值是17.2

输入单个字符

Scanner 没有直接读入单个字符的方法,next 方法没办法读入空格符,因为 Scanner 以空格符作为输入完毕的标志

import java.util.Scanner;  
Scanner in = new Scanner(System.in);  
String s = in.nextLine();  
char[] chars = s.toArray();
char c = chars[0];  //c就是读入的单个字符

输出

C++

cout 输出控制浮点数比较麻烦,建议使用 scanf

cout就是普通的输出

java

1、换行打印“System.out.println()”;
2、不换行打印“System.out.print()”;
3、按格式输出“System.out.printf()”。
System.out.println(); 是最常用的输出语句,它会把括号里的内容转换成字符串输出到输出窗口(控制台),并且换行,当输出的是一个基本数据类型时,会自动转换成字符串,如果输出的是一个对象,会自动调用对象的 toString(); 方法,将返回值输出到控制台
System.out.print(); 与第一个很相似,区别就是上一个输出后会换行,而这个命令输出后并不换行。
System.out.printf(); 这个方法延续了 C 语言的输出方式,通过格式化文本和参数列表输出。

C

prinf 格式化输出