C++&Java字符串输入输出

本文详细介绍了C++中cin、getline和scanf等输入函数的使用,包括它们的输入结束条件、对结束符的处理以及如何处理缓冲区中的残留数据。特别强调了不同函数在读取字符串时的区别,如cin会跳过空格和换行符,getline则读取整行直到遇到换行符,而scanf则根据空格分隔读取。此外,还提及了Java中的Scanner类及其相关方法。内容涵盖了输入缓冲区的概念,以及如何避免因缓冲区残留数据导致的输入问题。

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 格式化输出

<think> 根据用户的问题,用户需要了解C++字符串二维数组的输入输出方法。结合引用内容,我注意到引用[1]和引用[3]提供了相关的方法。特别是引用[3]中有一个示例函数`stringToIntegerMatrix1`,它处理的是整数二维数组,但我们可以借鉴其思路来处理字符串二维数组。 用户要求的是字符串二维数组,所以需要存储的是`string`类型。我们可以考虑以下情况: 1. 输入格式:用户可能以不同的格式输入,比如每行一个字符串数组,用空格分隔,然后多行输入;或者输入一个类似`[[str1,str2],[str3,str4]]`的格式(如引用[3]中的整数矩阵输入)。 2. 输出格式:相应地输出二维字符串数组。 但是,用户并没有指定输入格式,所以我们需要提供常见的几种输入方式。 根据引用[1]中的内容,有几种输入方式: - 输入多个字符串,每个串之间以空格作为结束;最终结束是回车(即一行字符串,空格分隔,回车结束一行,然后可以有多行) - 输入不定矩阵,以回车结尾(即行数不定,每行字符串数也不定?) 另外,引用[3]提供了一种解析特定格式字符串的方法(例如`[[1,2,3],[4,5,6]]`),我们可以将其扩展到字符串。 因此,我将提供两种常见情况的示例: 情况1:逐行输入,每行由空格分隔的多个字符串组成,直到遇到空行或结束标志。 情况2:输入一个类似`[["str1","str2"],["str3","str4"]]`的字符串,然后解析成二维字符串数组。 同时,输出时,我们可以按照行输出,每行内的字符串用空格分隔,或者按照类似二维数组的格式输出。 由于用户要求输入输出方法,我将分别给出输入和输出的代码示例。 注意:在C++中,字符串二维数组通常用`vector<vector<string>>`来表示,这样更灵活。 方案1:逐行输入,每行用空格分隔多个字符串,直到输入空行(或指定行数) 方案2:解析特定格式的字符串(如JSON格式,但这里简化处理) 下面分别给出两种方案的代码: 方案1:逐行输入,直到遇到空行(或者也可以指定行数) 输入示例: hello world this is a test (然后输入一个空行结束) 代码: ```cpp #include <iostream> #include <vector> #include <string> #include <sstream> using namespace std; int main() { vector<vector<string>> str2DArray; string line; cout << "请输入字符串矩阵,每行用空格分隔多个字符串,空行结束:" << endl; while (getline(cin, line)) { if (line.empty()) // 空行结束输入 break; vector<string> row; stringstream ss(line); string word; while (ss >> word) { row.push_back(word); } str2DArray.push_back(row); } // 输出二维字符串数组 cout << "输出结果:" << endl; for (const auto& row : str2DArray) { for (const auto& s : row) { cout << s << " "; } cout << endl; } return 0; } ``` 方案2:解析特定格式的字符串,如`[["str1","str2"],["str3","str4"]]`。注意,这个解析相对复杂,因为字符串中可能包含逗号、空格等。我们假设输入的字符串格式是标准的,每个字符串用双引号括起来,且字符串内不包含双引号和逗号(或者我们可以用转义,但这里简化处理)。 我们参考引用[3]中的整数矩阵解析方法,修改为处理字符串。 输入示例:`[["hello","world"],["this","is","a","test"]]` 代码: ```cpp #include <iostream> #include <vector> #include <string> #include <sstream> #include <cctype> using namespace std; vector<vector<string>> parseStringMatrix(string input) { vector<vector<string>> matrix; // 去除输入字符串首尾的方括号 if (input.front() == '[') input = input.substr(1, input.size()-2); else return matrix; vector<string> row; string token; bool inQuotes = false; bool inBracket = false; // 是否在行向量中(即[ ... ]内部) for (size_t i=0; i<input.size(); ) { if (input[i]=='[') { inBracket = true; row.clear(); i++; } else if (input[i]==']') { inBracket = false; // 将当前行加入矩阵 matrix.push_back(row); row.clear(); // 跳过逗号和可能的空格 i++; while (i<input.size() && (input[i]==',' || input[i]==' ')) i++; } else if (inBracket && input[i]=='"') { // 开始一个字符串 inQuotes = true; token = ""; i++; while (i<input.size() && inQuotes) { if (input[i]=='\\') { // 转义字符 if (i+1 < input.size()) { token += input[i+1]; i += 2; } } else if (input[i]=='"') { inQuotes = false; i++; } else { token += input[i]; i++; } } // 将token加入当前行 row.push_back(token); // 跳过逗号和空格 while (i<input.size() && (input[i]==',' || input[i]==' ')) i++; } else { i++; // 其他情况,跳过(比如空格等) } } return matrix; } int main() { string input; cout << "请输入格式为[[\"str1\",\"str2\"],[\"str3\"]]的字符串:" << endl; getline(cin, input); vector<vector<string>> matrix = parseStringMatrix(input); // 输出 cout << "解析后的二维字符串数组:" << endl; for (const auto& row : matrix) { for (const auto& s : row) { cout << s << " "; } cout << endl; } return 0; } ``` 注意:方案2的解析器是一个简化版本,它假设输入的格式是严格正确的。实际应用中可能需要更健壮的解析,比如处理转义字符、错误格式等。 另外,引用[1]中还提到了其他输入方式,比如输入单字符串、多个字符串等,但用户特别关注二维数组,所以我们重点在二维数组的输入输出。 总结:在C++中,处理字符串二维数组的输入输出,通常使用`vector<vector<string>>`来存储。输入方式可以根据实际需要选择逐行读取空格分隔的字符串,或者解析特定格式的字符串。 根据用户的问题,我提供了两种常见的方法。用户可以根据自己的输入格式选择合适的方法。 注意:在方案2中,我们假设字符串是用双引号括起来的。如果输入中没有双引号,而是用单引号或者没有引号,则需要调整解析逻辑。 最后,我们也可以使用现有的库(如JSON库)来解析复杂的格式,但这里为了简单,我们自行解析。 如果用户需要更详细的信息,可以参考引用[1]和引用[3]中的方法。 希望这些方法能够帮助用户解决问题。 </think>### C++字符串二维数组的输入输出方法 在C++中处理字符串二维数组的输入输出需要根据不同的数据格式灵活实现。以下是常见的三种实现方式,涵盖不同输入场景: #### 1. **逐行输入空格分隔的字符串(动态行数列数)** ```cpp #include <iostream> #include <vector> #include <string> #include <sstream> using namespace std; int main() { vector<vector<string>> str2D; string line; // 输入:每行多个空格分隔的字符串,空行结束 cout << "输入字符串矩阵(空格分隔,空行结束):\n"; while (getline(cin, line) && !line.empty()) { vector<string> row; stringstream ss(line); string word; while (ss >> word) { row.push_back(word); } str2D.push_back(row); } // 输出二维数组 cout << "输出结果:\n"; for (auto &row : str2D) { for (auto &s : row) { cout << s << " "; } cout << "\n"; } return 0; } ``` **输入示例**: ``` hello world cpp 2d array [空行] ``` **输出**: ``` hello world cpp 2d array ``` #### 2. **解析JSON格式的字符串矩阵(如`[["a","b"],["c"]]`)** ```cpp #include <iostream> #include <vector> #include <string> using namespace std; vector<vector<string>> parseStringMatrix(string input) { vector<vector<string>> matrix; vector<string> row; string token; bool inString = false; bool inVector = false; for (char c : input) { if (c == '[') { if (inVector) row.clear(); inVector = true; } else if (c == ']') { if (!token.empty()) { row.push_back(token); token = ""; } if (inVector && !row.empty()) { matrix.push_back(row); row.clear(); } inVector = false; } else if (c == '\"') { inString = !inString; if (!inString && !token.empty()) { row.push_back(token); token = ""; } } else if (inString) { token += c; } } return matrix; } int main() { string input = R"([["Hello","World"],["C++","2D","Array"]])"; auto matrix = parseStringMatrix(input); // 输出结果 for (auto &row : matrix) { for (auto &s : row) { cout << s << " "; } cout << "\n"; } return 0; } ``` **输出**: ``` Hello World C++ 2D Array ``` #### 3. **固定行数的逗号分隔输入** ```cpp #include <iostream> #include <vector> #include <string> #include <sstream> using namespace std; int main() { int rows; cout << "输入行数: "; cin >> rows; cin.ignore(); // 清除换行符 vector<vector<string>> str2D(rows); for (int i = 0; i < rows; ++i) { string line; cout << "输入第" << i+1 << "行(逗号分隔): "; getline(cin, line); stringstream ss(line); string cell; while (getline(ss, cell, ',')) { str2D[i].push_back(cell); } } // 输出 for (auto &row : str2D) { for (int j = 0; j < row.size(); ++j) { cout << row[j]; if (j < row.size()-1) cout << ", "; } cout << "\n"; } return 0; } ``` **输入示例**: ``` 3 apple,banana C++,Python,Java one,two,three ``` **输出**: ``` apple, banana C++, Python, Java one, two, three ``` ### 关键点说明 1. **输入处理**: - 使用`getline()`读取整行避免空格截断[^1] - 通过`stringstream`分割单词/逗号分隔值 - 引号处理需手动解析字符串边界 2. **数据结构**: - 推荐`vector<vector<string>>`动态存储 - 每行可以是不同长度的字符串数组[^4] 3. **特殊格式**: - JSON格式需处理`[ ] , " `等符号边界 - 引号内内容需完整保留(含空格)[^3] 4. **输出控制**: - 内层循环输出每行元素 - 分隔符保持与输入一致 > 提示:实际应用时需根据输入格式选择对应方案,对带空格的字符串建议用双引号包裹保证完整性[^1][^3]。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值