关于c++字符输入的读取,你只需要这看这一篇就够了

前言:

!!!阅读前最好先看前言和目录

通过阅读这篇文章,你可以学会什么:

  • cin.get()和get()它们的区别是什么?
  • 各种输入方法,它们输入终止的条件是什么?是遇到空格,还是换行符?
  • 如何一次性从键盘读取多行字符?
  • cin.eof(),cin.fail()等等,这些是什么,它们的意义是什么?

一.cin流对象和与输入有关的全局函数

输入流的概念

首先,我们介绍一个概念:输入流

输入流(Input Stream)是计算机编程中用于从某个源获取数据的概念。输入流可以是文件、键盘、网络连接等。在C++中,输入流通常用于从标准输入设备(例如键盘)或文件中读取数据。

C++标准库提供了 istream 类,istream 支持从不同源读取数据的方法,并提供了一些用于处理输入的函数。cinistream 类的一个实例,cin流下的对象用于从标准输入设备(键盘)读取数据。而包括get,getline在内的全局函数,也具备从输入流中读取字符的功能。

因此,在c++中,从键盘中得到输入,最常见的两种方法就是使用cin流对象和与输入有关的全局函数。下面是它们一些主要的区别:

二者的区别

1.类型:
  • 输入流(如 cin): 属于输入流类 (istream),是面向对象的。cin 是 istream 类的一个实例,提供了一些丰富的成员函数,可以用于不同类型的输入操作。
  • 全局函数(如 get): 这些函数是全局函数,通常较为简单,专注于读取字符。
2.方便性和易用性:
  • 输入流: cin 提供了方便且易用的输入方式,可以直接使用 >> 运算符进行输入。它会根据变量的类型进行格式化的输入。
  • 全局函数: 使用全局函数可能需要更多的手动处理,特别是在需要对输入进行更精细的控制时。例如,处理换行符、空格等。
3.输入控制:
  • 输入流: cin 有一些内建的机制,可以处理空格、制表符,并会自动跳过它们。它也能够自动转换输入为适当的类型。
  • 全局函数: 全局函数如 get 可以更灵活地处理输入,但也需要程序员显式地控制读取的内容。
4.错误处理:
  •  输入流: cin 可以触发流状态位,从而进行错误处理。例如,如果期望读取一个整数,但输入了非数字字符,cin 的状态位将被设置,允许你进行相应的错误处理。
  • 全局函数: 一些全局函数可能不提供像 cin 那样的丰富的错误处理机制。

综合来说,使用 cin 是更常见和更简单的方式,适用于大多数一般的输入需求。全局函数提供了更底层的控制,适用于一些特殊的输入场景,但通常会显得更冗长和手动。选择使用哪种方式取决于你的具体需求和编程风格。

二.cin流对象

`cin` 是 C++ 标准库中的标准输入流对象,属于 `istream` 类的实例。除了 `cin`,`istream` 类还有一些其他常用的函数和对象,用于从输入流中读取数据。以下是其中一些:

 cin的基本用法

在使用cin时,它默认使用空格作为分隔符,因此如果你需要输入包含空格的字符串,可能需要采用不同的方法。以下是一些关于字符输入的说明:

读取单个字符:

char ch;
cin >> ch;

 读取字符串:

string str;
cin >> str;  // 读取到空格为止

cin流对象的基本用法

1. cin.get() 函数
  •    get 函数用于从输入流中读取一个字符。
  •    函数声明:int get();(get 函数返回一个整数,它可以是读取的字符的 ASCII 值(0 到 255)或者特殊值 EOF
  •  在一些编译器中,cin.get()与cin.getline() 的功能基本相同,只是不将截止标志储存到字符串中
char ch;
ch = cin.get(); // 读取单个字符
2. cin.getline() 函数
  •    getline 函数用于从输入流中读取一行字符串,包括换行符,并将其存储到字符串中。
  •     函数声明:istream& getline(char* s, streamsize n, char delim = '\n');(streamsize表示字符的数量,delim是截止符的意思)
  •    getline默认的截止符是 '\n',即换行符,可以在第三个形式参数中为它设置截止符
  • !!!值得一提的是,如果使用
string line;
cin.get(line,100)

这种读取方法是错误的,因为参数形式不一致,应该使用getline函数直接进行读取,后面会提到。

char buffer[256];
cin.getline(buffer, 256); // 读取一整行,可以包含空格
3. cin.ignore() 函数
  •    ignore函数用于忽略输入流中的字符,可以指定要忽略的字符数或者遇到的分隔符。
  •    函数声明:`istream& ignore(streamsize n = 1, int delim = EOF);
  • 如果在 ignore 达到指定的总字符数之前遇到了指定的分隔符(或者达到文件末尾),ignore提前停止忽略字符,并将流状态标志设置为 eofbit(如果是到达文件末尾)或 failbit(如果是遇到指定的分隔符)。(流状态的设置会在后面说明)
cin.ignore(100, '\n'); 
// 忽略输入流中的前100个字符或者直到遇到换行符
4. cin.peek() 函数:
  •    peek 函数用于查看输入流中的下一个字符,但不从流中提取它。
  •    函数声明:int peek();
char nextChar = cin.peek(); // 查看下一个字符,但不提取
5. cin.putback() 函数
  •    putback函数用于将一个字符放回输入流中,使其成为下一个被读取的字符。
  •    函数声明:istream& putback(char c);
cin.putback('A'); // 将字符 'A' 放回输入流中

三.与输入有关的全局函数

在C++中,有一些全局函数可以用于从输入流中读取字符。以下是其中一些常见的:

1. get:
  •    get 函数用于从输入流中读取一个字符,并返回其 ASCII 值。
  •    可以使用 `get()` 读取一个字符。
  •    可以指定一个分隔符,get(delimiter) 会读取并丢弃一个字符。
  • !!!get是一个古老的函数,在如codeblocks的编译器中并不支持以下的代码
char ch;
ch = get(); // 读取单个字符

char delimiter;
get(delimiter); // 读取并丢弃一个字符,可以用于处理分隔符
2. getline:
  •     getline 函数用于从输入流中读取一行string类字符串,直到遇到换行符,并不将换行符存储到变量中。
  •     可以用于读取整行,包括空格。
    string line;
   getline(cin,line);

 注意:

char line[256]; getline(cin, line); 这种用法是存在问题的。getline 函数的第二个参数应该是 std::string 类型的对象,而不是字符数组。getline 函数用于从输入流中读取一行字符串,并将其存储到字符串对象中,而不是字符数组。

如果你想使用字符数组来存储输入的一行字符串,你可以使用 cin.getline 函数

3. getchar:
  •    getchar 函数用于从输入流中读取一个字符,并返回其 ASCII 值。
char ch = getchar(); // 读取单个字符
4. gets:
  •    gets 函数用于从输入流中读取一行字符串,直到遇到换行符。
  •    注意:gets 已经被标记为不安全,不推荐在现代C++中使用,因为它无法防止缓冲区溢出。

这些全局函数提供了一些不同的方式来处理输入,你可以根据具体的需求选择合适的函数。在现代C++中,更推荐使用 `getline` 和 `cin` 对象来进行输入操作,因为它们提供了更安全和更灵活的机制。

关于合法性的问题,这些函数在现代 C++ 中仍然是有效的,但在一些特定的编译器或环境中,可能会有一些差异。如果在 Code::Blocks 或其他 IDE 中出现问题,可以检查编译器的设置和标准库的配置。通常情况下,这些函数应该是可用的。

四.如何读取多行的字符串

        在输入的读取过程中,有时候我们需要读取包括空格,换行符在内的符号,通过前面的讲解,我们知道了使用cin.getline(),getlint(cin, )可以读取包括空格在内的多行变量,但遇到换行符'\0'这样的空白符,还是会停止读取。那如何一次性读取多行字符呢?

        首先,一个比较自然的想法是用cin.getline( , ,'\0'),如果将空字符作为输入的截止字符,那就可以接受所有输入的字符了,但这样也存在一些问题,在codeblocks这样的编译器中,没有特殊设置,可能是不支持用Ctrl+z等方法强制停止输入的,这样就会导致代码运行时只能一直输入。实际上,通过函数本身来做到多行输入的读取是很难做到的。所以,我们应该寻找其他方法来做到多行输入的读取,这个方法,就是循环的使用

1.利用循环和数组读取多行字符串
#include <iostream>

using namespace std;

int main() {
    const int maxLines = 100;  // 假设最多读取100行
    const int maxLineLength = 256;  // 假设每行最多256个字符

    char ch[maxLines][maxLineLength];
    int lineCount = 0;


    // 逐行读取文本
    while (lineCount < maxLines && cin.getline(ch[lineCount], maxLineLength) && ch[lineCount][0] != '\0') {
        lineCount++;
    }

    return 0;
}

这是一个用二维数组读取最多100行,每行最多256个字符的代码 。当读取到空白行时,停止读取。实际上,遇到第一个空白行后停止,就是通常情况下我们用于读取多行字符串的方法。

但有时候,二维数组的使用,可能会使我们对字符串的处理变得麻烦,那有没有办法使用一维数组解决呢。如果是自己编译的过程中,我们可以通过条件设置来控制输入的截止,如果在给定的测试中,方法就比较多样了。例如,我们可以用cin.eof()作为条件判断的标志,如以下代码:
 

#include <iostream>
#include <string>
using namespace std;

int main() {
    const int maxSize = 10000;
    char ch[maxSize];
    int i = 0;

    while (i < maxSize - 1 && cin.get(ch[i])) {
        // 检查是否已到达文件末尾
        if (ch[i] == EOF) {
            break;
        }
        i++;
    }

    // 添加 null 结尾标记
    ch[i] = '\0';

    // 输出字符数组
    cout << ch;

    return 0;
}

当然,这样使用是无法再我们自己编译时手动终止输入的。在后面调用时,我们可以用

for(int i=0;ch[i]!='\0';i++)来调用 

2.利用循环和string类
#include <iostream>
#include <string>

using namespace std;

int main() {
    string totalline,line;
    while (true) {
        // 读取一行字符,包括换行符
        getline(cin, line);
        // 如果输入为空行,退出循环
        if (line.empty()) {
            break;
        }
        totalline+=line+'\n';//实现分行读取后合并

    }
    cout<<totalline;

    return 0;
}

除此之外,我们还可以用vector,stringstream处理多行文本,这些属于后面的知识,暂时不补充了。

五.流状态的设置

在C++中,流(stream)是一种用于输入和输出的抽象概念。流状态是描述流的当前状态的一组标志,用于指示流的可用性和发生的事件。C++标准库提供了一些函数和标志,以便在程序中检查和处理流的状态。

以下是一些常见的流状态和相关的标志:

1. goodbit:
  •    goodbit 是流状态的默认初始状态。
  •    当流状态正常,没有错误发生时,`goodbit` 被设置。
  •    通过 good()成员函数来检查流是否处于正常状态。
2. eofbit:
  •    eofbit 表示流已经到达文件末尾(End of File)。
  •    当读取操作尝试读取文件末尾之后的数据时,`eofbit` 被设置。
  •    通过 eof() 成员函数来检查流是否已到达文件末尾。cin.eof()与cin.get()==EOF这两种写法在检查是否达到结尾上是相似的,但不完全等价。使用 cin.eof() 更多地关注流的状态,而 cin.get() == EOF 更侧重于具体的字符读取和 EOF 常量的比较。
3. failbit:
  •    failbit 表示一个非致命的错误,可能会导致流不再可用。
  •    例如,当试图读取一个整数,但输入的数据不是整数时,failbit 被设置。还比如,提前达到了上面cin.ignore()的截止符。
  •    通过 fail() 成员函数来检查是否发生了非致命的错误。
4. badbit:
  •    badbit 表示致命的错误,导致流不再可用。
  •    例如,当底层设备发生故障时,`badbit` 被设置。
  •    通过 bad() 成员函数来检查是否发生了致命的错误。

这些标志可以通过成员函数 `clear()` 来清除,并可以通过 `setstate()` 来设置

具体的使用方法:

#include <iostream>

using namespace std;

int main() {
    int value;

    cout << "Enter an integer: ";
    
    // 尝试读取输入
    cin >> value;

    if (cin.good()) {
        // 输入正常,没有错误
        cout << "You entered: " << value << std::endl;
    } else if (cin.eof()) {
        // 到达文件末尾
        cout << "Reached end of file." << std::endl;
    } else if (cin.fail()) {
        // 非致命错误,例如输入不是整数
        cerr << "Invalid input. Please enter an integer." << endl;
        cin.clear();  // 清除错误标志
        cin.ignore(1, '\n');  // 忽略当前字符
        cin>>value;
    } else if (cin.bad()) {
        // 致命错误,例如底层设备故障
        cerr << "Fatal error occurred." << endl;
        return 1;  // 退出程序或采取适当的错误处理措施
    }

    return 0;
}

编译器检测输入,并设置相应的的流状态。而通过cin.good()等方式,我们可以对当前的流状态进行检测,如果输入正常,cin.good()返回true,以此类推。

流状态在C++中的作用主要是提供一种机制来检测和处理输入/输出操作中的异常情况,例如文件末尾、无效输入等。通过检查流的状态,你可以更好地控制程序的行为,避免程序因为输入错误而崩溃或产生不可预测的结果。根据流的状态,你可以动态地调整程序的行为。例如,如果输入包含非法字符,你可能会选择提示用户重新输入,而不是继续使用无效的输入。

总体而言,流状态提供了一种机制,让你能够更灵活地处理输入和输出,以及更好地应对各种潜在的错误情况。这有助于提高程序的可靠性。

  • 5
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值