C++ getline() 和 get()

字符串输入问题

#include <iostream>
using namespace std;

int main()
{
    const int Asize = 20;
    char name[Asize];
    char dessert[Asize];

    cout << "Enter your name:" <<endl;
    cin >> name;
    cout << "Enter your favorite dessert:" <<endl;
    cin >> dessert;
    cout << "I have some delicious " << dessert;
    cout << "for you, " << name << endl;
    return 0;
}

在没有输入你最喜欢的甜点的提示下,程序就把它显示出来了,然后立即显示最后一行。这是因为 cin 使用空白(空格、制表符和换行符)来确定字符串的结束位置,这意味着 cin 在获取字符串数组输入时只读取空格前的一个单词。读取该单词后,cin 将该字符串放到数组中,并自动在结尾添加空字符。

为了能读取一行字符串输入,cin 提供了一些面向行的类成员函数:getline() 和 get()。这两个函数都读取一行输入,直到到达换行符。然而,随后 getline() 会丢弃换行符,而 get() 将换行符保留在输入序列中。下面详细介绍它们,首先介绍 getline()。

 

面向行的输入:istream& getline(char *p, int n, char c)

getline() 函数读取整行,它使用通过回车键输入的换行符来确定输入结尾。要调用这种方法,可以使用 cin.getline()。该函数有两个参数。第一个参数是用来存储输入行的数组的名称,第二个参数是要读取的字符数量。如果参数是 20,那么最多可以读取 19 个字符,余下的空间用于存储自动在结尾处添加的空字符如果在读取 n-1 个字符之前遇到终止字符(第三个参数不写,默认为 '\n' ),则提前结束。getline() 成员函数在读取指定数目的字符或遇到换行符时停止读取。

#include <iostream>
using namespace std;

int main()
{
    const int Asize = 20;
    char name[Asize];
    char dessert[Asize];

    cout << "Enter your name:" <<endl;
    cin.getline(name, Asize);
    cout << "Enter your favorite dessert:" <<endl;
    cin.getline(dessert, Asize);
    cout << "I have some delicious " << dessert;
    cout << "for you, " << name << endl;
    return 0;
}

getline(cin, inputLine),其中 cin 是正在读取的输入流,而 inputLine 是接收输入字符串的 string 变量的名称。需要注意的是,它不是类方法。

#include <iostream>
#include <string> // Header file needed to use string objects
using namespace std;
int main()
{
    string name;
    string city;
    cout << "Please enter your name: ";
    getline(cin, name);
    cout << "Enter the city you live in: ";
    getline(cin, city);
    cout << "Hello, " << name << endl;
    cout << "You live in " << city << endl;
    return 0;
}

 

面向行的输入:istream& get(char *p, int n, char c)

另一个名为 get() 的成员函数,该函数有几种变体。其中一种变体的工作方式和 getline() 类似,它们接受的参数相同,解释参数的方式也相同,并且都读取到行尾。情况1:当输入的字符数小于 n 时遇到终结符,get() 并不再读取并丢弃终结符,而是将其留在输入队列中。而 getline 函数将读取这个字符但是不存进 p 所指的数组中,而是将其丢弃。当然,两者都会在读取的字符串后面自动加上 '\0'。假设我们连续两次调用 get():

cin.get(name, Asize);
cin.get(dessert, Asize);    //dessert没有内容

由于第一次调用后,换行符将留在输入队列中,因此第二次调用时看到第一个字符便是换行符。因此 get() 认为已到达行尾,而没有发现任何可读取的内容。如果不借助于帮助,get() 将不能跨过该换行符。这时可以使用 get() 的另一种变体。使用不带任何参数的 cin.get() 调用可读取下一个字符(即使是换行符)。

cin.get(name, Asize);
cin.get();
cin.get(dessert, Asize);

另一种使用 get() 的方式是将两个类成员函数拼接起来:

cin.get(name, Asize).get();

之所以可以这样做,是由于 cin.get(name, Asize) 返回一个 cin 对象,该对象随后将被用来调用 get() 函数。同样,下面的语句将输入中连续的两行分别读入到数组 name1 和数组 name2 中,其效果与两次调用 cin.getline() 相同:

cin.getline(name1, Asize).getline(name2, Asize);
#include <iostream>
using namespace std;

int main()
{
    const int Asize = 20;
    char name[Asize];
    char dessert[Asize];

    cout << "Enter your name:" <<endl;
    cin.get(name, Asize).get();
    cout << "Enter your favorite dessert:" <<endl;
    cin.get(dessert, Asize).get();
    cout << "I have some delicious " << dessert;
    cout << "for you, " << name << endl;
    return 0;
}

 

空格行和其他问题

当 getline() 或 get() 读取空格时,将发生什么情况?当 get() 读取空行后将设置失效位。这意味着接下来的输入将被阻断,但可以用下面的命令来恢复输入:cin.clear()。

情况2:另一个潜在的问题是,输入字符串可能比分配的空间要长。如果输入行包含的字符数比指定的多,则 getline() 和 get() 将把余下的字符留在输入队列中,对 get() 而言,可以用另一条读取函数来读取留在输入队列中的数据,也可以写一段代码将余下的字符清除。而 getline() 还会设置失效位,并关闭后面的输入。同样使用 cin.clear() 恢复输入。

#include <iostream>
using namespace std;

int main()
{
    cout << "What year was your house built?" <<endl;
    int year;
    cin >> year;
    cout << "What is its street address?" <<endl;
    char address[80];
    cin.getline(address, 80);
    cout << "Year built: " << year <<endl;
    cout << "Address: " << address <<endl;
    cout << "Done!" <<endl;
    return 0;
}

用户根本没有输入地址的机会。问题在于,当 cin 读取年份,将回车键生成的换行符留在了输入队列中。后面的 cin.getline() 看到换行符后,将认为是一个空行,并将一个空字符串赋予 address 数组。解决的方法是,在读取地址之前先读取并丢弃换行符。这可以通过使用没有参数的 get() 和使用接受一个 char 参数的 get():

cin >> year;
cin.get();   // or cin.get(ch);

也可以利用表达式 cin >> year 返回 cin 对象,将调用拼接起来:

(cin >> year).get();   //  or (cin >> year).get(ch);
#include <iostream>
using namespace std;

int main()
{
    cout << "What year was your house built?" <<endl;
    int year;
    (cin >> year).get();
    cout << "What is its street address?\n";
    char address[80];
    cin.getline(address, 80);
    cout << "Year built: " << year <<endl;
    cout << "Address: " << address <<endl;
    cout << "Done!" <<endl;
    return 0;
}

 

补充的一点:C++ 中 "\n" 与 endl 的区别

"\n" 表示内容为一个回车符的字符串。std::endl 是流操作,输出的作用和输出 "\n" 类似,但略有区别。

std::endl 输出一个换行符,并立即刷新缓冲区。

cout << endl;
相当于
std::cout << '\n';
std::fflush(stdout);
由于流操作符 << 的重载,对于 '\n' 和 "\n",输出效果相同。

对于有输出缓冲的流(例如 cout、clog),如果不手动进行缓冲区刷新操作,将在缓冲区满后自动刷新输出。不过对于 cout 来说(相对于文件输出流等),缓冲一般体现得并不明显。但是必要情况下使用 endl 代替 "\n"是个好习惯。对于无缓冲的流(例如标准错误输出流 cerr),刷新是不必要的,可以直接使用 "\n"。

已标记关键词 清除标记
相关推荐
©️2020 CSDN 皮肤主题: 编程工作室 设计师:CSDN官方博客 返回首页