C++ std::getline() 函数详解:用法、示例与常见问题

这是文章《如何在C++中使用std::getline()函数?》的第1部分(共4部分)。

在本文中,我们将深入探讨在C++中使用std::getline()函数。如果您需要从输入流中读取字符或整行内容,这是一个非常方便且强大的函数。

让我们通过一些具体的例子,详细了解如何正确地使用它。


C++中std::getline()函数的基本语法

std::getline()函数用于从输入流中读取字符,并将它们存储到一个字符串中。

为了使用std::getline(),我们需要引入<string>头文件,因为getline()是该头文件的一部分。此外,如果涉及文件操作,还需要引入<fstream>

尽管std::getline()的模板可以接受不同类型的参数,但我们主要关注其最常用的形式,即用于字符串输入(字符)的情况,因为其输出总是写入到字符串中。

istream& getline(istream& input_stream, string& output, char delim);

这个函数签名表明,getline()函数接受一个输入流(input_stream),并将读取到的内容写入到指定的输出字符串(output)中。可选的delim参数用于指定一个分隔符,当遇到该分隔符时,读取操作将停止。

getline()函数还会返回一个指向相同输入流的引用,但在大多数情况下,我们并不需要直接使用这个返回值。

使用std::getline()从输入流中读取内容

既然我们已经了解了基本的语法,让我们从标准输入流 std::cin 中获取字符串输入。

#include <iostream>
#include <string>

int main() {
    // 定义一个字符串变量用于存储姓名
    std::string name;

    std::cout << "请输入您的姓名: ";

    // 从std::cin获取输入并存储到name中
    std::getline(std::cin, name);

    std::cout << "你好," << name << "!\n";

    return 0;
}

输出:

请输入您的姓名: JournalDev
你好,JournalDev!

确实,我们能够毫无问题地从std::cin中获取输入!

现在让我们看另一个例子。假设我们有一个名为input.txt的文件,其中包含以下内容:

$ cat input.txt
Hello from JournalDev
Second Line of file
Last line

现在,让我们一行一行地读取这个文件,并将每一行存储到一个字符串向量中!

核心逻辑是持续使用std::getline(file, temp)读取,直到输入流达到文件末尾(EOF)。

我们可以轻松地用以下格式来实现:

std::ifstream infile("input.txt");

// 临时缓冲区
std::string temp;

// 从输入文件中获取内容,直到文件末尾
while (std::getline(infile, temp)) {
  // 添加到输出字符串列表中
  outputs.push_back(temp);
}

以下是完整的代码:

#include <iostream>
#include <string>
#include <vector>   // 用于 std::vector
#include <fstream>  // 用于 std::ifstream 和 std::ofstream

int main() {
    // 将文件内容存储到字符串向量中
    std::vector<std::string> outputs;

    std::cout << "正在从 input.txt 读取...\n";

    // 创建文件输入流对象
    std::ifstream infile("input.txt");

    // 临时缓冲区
    std::string temp;

    // 从输入文件中获取内容,直到文件末尾
    while (std::getline(infile, temp)) {
        // 添加到输出字符串列表中
        outputs.push_back(temp);
    }

    // 使用基于范围的for循环遍历输出向量
    for (const auto& i : outputs)
        std::cout << i << std::endl;

    return 0;
}

输出:

正在从 input.txt 读取....
Hello from JournalDev
Second Line of file
Last line

在C++中使用std::getline()函数以分隔符拆分输入

除了默认的换行符 \n,我们还可以利用 std::getline() 函数的第三个参数——分隔符(delim),来指定自定义的输入分割字符。

默认情况下,std::getline() 将换行符(\n)作为输入流的默认分隔符。然而,我们可以轻松修改此设置,使其根据其他字符进行输入分割。

现在,让我们将上述示例中的分隔符更改为空格字符 ' ',并观察其效果!

#include <iostream>
#include <string>
#include <vector> // 用于 std::vector
#include <fstream> // 用于 std::ifstream 和 std::ofstream

int main() {
    // 将内容存储到字符串向量中
    std::vector<std::string> outputs;

    std::cout << "正在从 input.txt 读取数据....\n";

    // 创建文件对象(输入)
    std::ifstream infile("input.txt");

    // 临时缓冲区
    std::string temp;

    // 从输入文件中获取数据,直到文件结束(EOF)
    while (std::getline(infile, temp, ' ')) {
        // 添加到输出字符串列表中
        outputs.push_back(temp);
    }

    // 使用基于范围的 for 循环遍历输出向量
    for (const auto& i : outputs)
        std::cout << i << std::endl;

    return 0;
}

输出

正在从 input.txt 读取数据....
Hello
from
JournalDev
Second
Line
of
file
Last
line

正如所料,我们现在成功地获得了以空格分隔的字符串!


使用 std::getline() 可能存在的问题

这是文章《如何在C++中使用std::getline()函数?》的第3部分(共4部分)。

尽管`std::getline()`是一个非常有用的函数,但当与某些输入流(如`std::cin`)一起使用时,可能会遇到一些问题。

  • `std::getline()`不会忽略任何开头的空白字符或换行符。

因此,如果在调用`getline()`之前调用`std::cin >> var;`,在读取输入变量后,输入流中仍会残留一个换行符。

如果你在`cin`之后立即调用`getline()`,你会得到一个换行符,因为它是输入流中的第一个字符!

为了避免这种情况,只需添加一个“虚拟”的`std::getline()`调用来消耗这个换行符!

以下程序展示了在使用`getline()`之前使用`cin`时存在的问题。

#include <iostream>
#include <string>

int main() {
    // 定义一个字符串变量用于存储姓名
    std::string name;

    int id;

    std::cout << "请输入ID: ";

    std::cin >> id;

    std::cout << "请输入姓名: ";

    // 注意:上一个输入操作是std::cin!
    std::getline(std::cin, name);

    std::cout << "ID: " << id << std::endl;
    std::cout << "姓名: " << name << "\n";

    return 0;
}

产出:

请输入ID: 10
请输入姓名: ID: 10
姓名: 

注意到我根本无法输入姓名!由于输入流中存在一个尾随的换行符,`getline()`只是读取了该字符,并且因为它是一个分隔符,所以停止了继续读取!

现在让我们在实际的`std::getline()`调用之前添加一个“虚拟”的`std::getline()`调用。

#include <iostream>
#include <string>

int main() {
    // 定义一个字符串变量用于存储姓名
    std::string name;

    int id;

    std::cout << "请输入ID: ";

    std::cin >> id;

    std::cout << "请输入姓名: ";

    // 添加一个虚拟的getline()调用来消耗换行符
    std::getline(std::cin, name);
    // 注意:上一个输入操作是std::cin!
    std::getline(std::cin, name);

    std::cout << "ID: " << id << std::endl;
    std::cout << "姓名: " << name << "\n";

    return 0;
}

产出:

请输入ID: 10
请输入姓名: JournalDev
ID: 10
姓名: JournalDev

我们终于修复了我们的错误!希望这会让你在盲目使用`std::getline()`之前多加思考。

很遗憾,C++中没有特别优雅的方法来获取输入,所以我们必须利用现有方法来解决问题!


结论

在本文中,我们学习了如何在C++中使用std::getline()函数。我们还通过一些示例,展示了这个函数的强大功能和潜在的陷阱。

参考资料


bannerAds