如何在 C++ 中使用 getline 命令?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/9124583/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to use the getline command in c++?
提问by Gvegas222
I'm trying to turn a cout command into a getline command in c++.
我正在尝试将 cout 命令转换为 c++ 中的 getline 命令。
This is my code that I'm trying to changes....
这是我正在尝试更改的代码....
for (int count=0; count < numberOfEmployees; count++)
{
cout << "Name: ";
cin >> employees[count].name;
cout << "Title: ";
cin >> employees[count].title;
cout << "SSNum: ";
cin >> employees[count].SSNum;
cout << "Salary: ";
cin >> employees[count].Salary;
cout << "Withholding Exemptions: ";
cin >> employees[count].Withholding_Exemptions;
}
I'm trying to change this line: cin >> employees[count].name;
and this line: cin >> employees[count].title;
into getlines. Can anyone help?
我正在尝试将这一行:cin >> employees[count].name;
和这一行:更改cin >> employees[count].title;
为 getlines。任何人都可以帮忙吗?
Thanks
谢谢
回答by Rohit Vipin Mathews
Flushing Problems with cin.getline() in C++
C++ 中 cin.getline() 的刷新问题
When you want to remove extraneous characters from an input stream in C++, it's usually because you mixed formatted and unformatted input methods. The formatted method would leave a newline in the stream and the unformatted method would consume it and terminate successfully, but fail completely to do what you wanted.
当您想从 C++ 中的输入流中删除无关字符时,通常是因为您混合了格式化和未格式化的输入方法。格式化的方法会在流中留下一个换行符,而未格式化的方法会使用它并成功终止,但完全无法执行您想要的操作。
#include <iostream>
int main() {
std::cout<<"Enter the letter A: ";
std::cin.get();
std::cout<<"Enter the letter B: ";
std::cin.get();
std::cout<<"Too late, you can't type anymore\n";
}
Often this question stems from another question, which is how to pause a program before it terminates. Using cin.get() works only when there are no characters left in the stream. The instant you throw a cin>> foo; in the code, suddenly the solution fails. You need to clear out any leftover characters from the stream before it'll work again.
通常这个问题源于另一个问题,即如何在程序终止之前暂停它。仅当流中没有剩余字符时,才使用 cin.get() 。当你扔出 cin>> foo; 在代码中,突然解决方案失败。您需要清除流中的所有剩余字符,然后才能再次运行。
So how do you fix the problem? The good news is that unless you want to get picky, it's as simple as a loop: C++ Syntax (Toggle Plain Text)
那么你如何解决这个问题呢?好消息是,除非你想挑剔,它就像一个循环一样简单:C++ 语法(切换纯文本)
#include <istream>
void ignore_line ( std::istream& in ) {
char ch;
while ( in.get ( ch ) && ch != '\n' );
}
This loop simply reads characters until end-of-file or a newline is read. It's generally assumed that interactive input in C++ is line-oriented and you're guaranteed to have a clean buffer after reading a newline. While that's not true (input doesn't have to be line-oriented), it's wide spread enough that we can assume it for the purposes of this thread.
这个循环只是读取字符,直到读取到文件结束或换行符。通常假设 C++ 中的交互式输入是面向行的,并且在读取换行符后保证您有一个干净的缓冲区。虽然这不是真的(输入不必是面向行的),但它的传播范围很广,我们可以假设它用于本线程的目的。
So what's wrong with this approach? Nothing. In fact, this is about as good as it gets unless you want to dig down and fix the subtle problems. But before we look at the problems, here's an alternative solution that does the same thing in a different way:
那么这种方法有什么问题呢?没有。事实上,除非您想深入挖掘并解决微妙的问题,否则这已经足够了。但在我们看问题之前,这里有一个替代解决方案,它以不同的方式做同样的事情:
#include <ios>
#include <istream>
#include <limits>
void ignore_line ( std::istream& in ) {
in.ignore ( std::numeric_limits<std::streamsize>::max(), '\n' );
}
The ignore member function of std::istream will read and discard up to N characters or until a delimiter. In the above example, N is represented by the largest value of the streamsize data type, and the delimiter is a newline. It works equally well with just a large value (80 is common): C++ Syntax (Toggle Plain Text) in.ignore ( 80, '\n' ); However, the streamsize data type is more likely to be an accurate representation of the size of the buffer that the stream is using, and it's more likely to work all of the time. This is the solution that I recommend.
std::istream 的 ignore 成员函数将读取并丢弃最多 N 个字符或直到一个分隔符。在上面的例子中,N用streamsize数据类型的最大值表示,分隔符是换行符。它同样适用于一个大值(80 是常见的): C++ Syntax (Toggle Plain Text) in.ignore ( 80, '\n' ); 但是,streamsize 数据类型更可能是流正在使用的缓冲区大小的准确表示,并且更有可能一直工作。这是我推荐的解决方案。
So what's wrong with this? There are two notable problems. The first is easy to fix, and it stems from the fact that istream isn't very flexible. istream is actually a typedef for basic_istream. If you want a wide stream to work with ignore_line, you're SOL with istream. So the trick is to use basic_istream<> instead:
那么这有什么问题呢?有两个值得注意的问题。第一个很容易修复,它源于 istream 不是很灵活的事实。istream 实际上是 basic_istream 的 typedef。如果您希望宽流与 ignore_line 一起使用,那么您就是 istream 的 SOL。所以诀窍是使用 basic_istream<> 代替:
#include <ios>
#include <istream>
#include <limits>
template <typename CharT>
void ignore_line ( std::basic_istream<CharT>& in ) {
in.ignore ( std::numeric_limits<std::streamsize>::max(), in.widen ( '\n' ) );
}
Now ignore_line is a template function that will derive the type of characters that the stream contains from the first argument. You can pass any stream that derives from or specializes basic_istream, and the problem is gone. Instead of just '\n', it's a good idea to use widen on the literal so that it will be properly converted to a wider type if necessary. Nice and easy.
现在 ignore_line 是一个模板函数,它将从第一个参数中导出流包含的字符类型。您可以传递源自或专门用于 basic_istream 的任何流,问题就消失了。不只是 '\n',最好在文字上使用加宽,以便在必要时将其正确转换为更宽的类型。好,易于。
The second problem is harder. Much harder. It's harder because standard iostreams seem to block your way at every turn with lack of portability or undesired features. In fact, it's impossible to completely fix the problem. The problem is that the behavior is different depending on the contents of the stream. For example:
第二个问题更难。难多了。这更难,因为标准的 iostream 似乎在每一个转弯处都挡住了你的去路,缺乏可移植性或不需要的功能。事实上,要彻底解决问题是不可能的。问题是行为因流的内容而异。例如:
#include <iostream>
#include <ios>
#include <istream>
#include <limits>
template <typename CharT>
void ignore_line ( std::basic_istream<CharT>& in ) {
in.ignore ( std::numeric_limits<std::streamsize>::max(), in.widen ( '\n' ) );
}
int main() {
std::cout<<"First input: ";
std::cin.get();
std::cout<<"Clearing cin.\n";
std::cin.clear();
ignore_line ( std::cin );
std::cout<<"All done.\n";
}
Run this program three times:
运行这个程序三遍:
Input: "asdf" Output: The program finishes without any more input from you.
输入:"asdf" 输出:程序结束时没有您的任何输入。
Input: Just hit Enter Output: The program waits for you to hit Enter one more time.
输入:只需按 Enter 输出:程序等待您再按一次 Enter。
Input: Signal EOF Output: The program waits for you to hit Enter one more time.
输入:信号 EOF 输出:程序等待您再按一次 Enter。
The problem is that the stream is empty. If you hit Enter immediately, a newline is placed on the stream and consumed by cin.get. Likewise with signaling EOF. At that point there's nothing left in the stream and cin.ignore stops everything until you type more characters. This is because cin.ignore is a blocking read. If there's nothing to read, it waits.
问题是流是空的。如果您立即按 Enter,则会在流上放置一个换行符并由 cin.get 使用。同样与信号EOF。此时,流中没有任何内容,cin.ignore 会停止所有内容,直到您键入更多字符。这是因为 cin.ignore 是阻塞读取。如果没有什么可读的,它会等待。
What we'd like it to do is not block for any of those three cases. The good news is that the iostream library supports some possible solutions. The bad news is that these are dead ends. Here are two common ones:
我们希望它做的不是阻止这三种情况中的任何一种。好消息是 iostream 库支持一些可能的解决方案。坏消息是这些都是死胡同。这里有两个常见的:
The sync member function The istream class supports a member function called sync. Why it has such a function is under debate, because nobody can agree on what it should be doing. Even Bjarne Stroustrup himself incorrectly stated that it discards all characters in the stream:
sync 成员函数 istream 类支持名为 sync 的成员函数。为什么它有这样的功能正在争论中,因为没有人就它应该做什么达成一致。甚至 Bjarne Stroustrup 本人也错误地指出它会丢弃流中的所有字符:
#include <iostream>
int main() {
std::cout<<"First input: ";
std::cin.get();
std::cout<<"Clearing cin.\n";
std::cin.clear();
std::cin.sync();
std::cout<<"All done.\n";
}
When this works, it works beautifully. The bad news is that the C++ standard doesn't require sync to do anything like discarding extraneous characters. This solution is non-portable.
当这工作时,它工作得很好。坏消息是 C++ 标准不需要同步来做任何事情,比如丢弃无关的字符。此解决方案不可移植。
The in_avail member function The next step is to look at the in_avail member function of istream's stream buffer. At first glance it looks like this member function will tell you how many characters are in the stream, and if it returns 0, you can refrain from calling ignore:
in_avail 成员函数接下来看istream 的流缓冲区的in_avail 成员函数。乍一看,这个成员函数会告诉你流中有多少个字符,如果它返回 0,你可以避免调用 ignore:
#include <iostream>
#include <ios>
#include <istream>
#include <limits>
template <typename CharT>
void ignore_line ( std::basic_istream<CharT>& in ) {
if ( in.rdbuf()->in_avail() > 0 )
in.ignore ( std::numeric_limits<std::streamsize>::max(), in.widen ( '\n' ) );
}
int main() {
std::cout<<"First input: ";
std::cin.get();
std::cout<<"Clearing cin.\n";
std::cin.clear();
ignore_line ( std::cin );
std::cout<<"All done.\n";
}
As with sync, when this works, it works great. But once again, the standard raises a wall by saying that in_avail isn't required to give you an accurate representation of the characters in the stream. In fact, some popular implementations have a strictly conforming in_avail that always returns 0. Not very useful. Now we have to get creative.
与同步一样,当它工作时,它工作得很好。但是,该标准再次提出了壁垒,称不需要 in_avail 来为您提供流中字符的准确表示。事实上,一些流行的实现有一个严格遵守的 in_avail 总是返回 0。不是很有用。现在我们必须发挥创意。
The putback member function
putback 成员函数
#include <iostream>
#include <ios>
#include <istream>
#include <limits>
template <typename CharT>
void ignore_line
( std::basic_istream<CharT>& in ) {
if ( !in.putback ( in.widen ( '\n' ) ) )
in.ignore ( std::numeric_limits<std::streamsize>::max(), in.widen ( '\n' ) ); else
in.ignore(); }
int main()
{ std::cout<<"First input: ";
std::cin.get();
std::cout<<"Clearing cin.\n";
std::cin.clear();
ignore_line ( std::cin );
std::cout<<"All done.\n";
}
This looks very promising because at first glance, it seems that you can attempt to push back a newline. If the operation fails, the last read character wasn't a newline and you're free to call ignore without blocking. If the operation succeeds, the newline is back and you can remove it with a single character ignore.
这看起来很有希望,因为乍一看,您似乎可以尝试推回换行符。如果操作失败,最后读取的字符不是换行符,您可以自由调用 ignore 而不阻塞。如果操作成功,换行符又回来了,您可以使用单个字符忽略将其删除。
Sadly, it doesn't work. putback isn't not required to do any of this predictably, which raises the question of why it's even available.
可悲的是,它不起作用。putback 不需要以可预见的方式执行任何这些操作,这引发了为什么它甚至可用的问题。
But putback actually takes us close to a solution that seems plausible enough to work most of the time. Instead of relying on putback to fail or not, we can guarantee that the last read character is put back by using the sungetc member function of the stream's buffer. The trick is to unget the last character, then read it again and test it against a newline:
但是回退实际上使我们接近了一个在大多数情况下似乎足够可行的解决方案。我们可以通过使用流缓冲区的 sungetc 成员函数来保证最后读取的字符被放回,而不是依赖于 putback 是否失败。诀窍是取消最后一个字符,然后再次读取它并针对换行符进行测试:
#include <iostream>
#include <ios>
#include <istream>
#include <limits>
template <typename CharT>
void ignore_line ( std::basic_istream<CharT>& in ) {
if ( in.rdbuf()->sungetc() != std::char_traits<CharT>::eof()
&& in.get() != in.widen ( '\n' ) ) {
in.ignore ( std::numeric_limits<std::streamsize>::max(), in.widen ( '\n' ) );
}
}
int main() {
std::cout<<"First input: ";
std::cin.get();
std::cout<<"Clearing cin.\n";
std::cin.clear();
ignore_line ( std::cin );
std::cout<<"All done.\n";
}
The reason we use sungetc instead of istream's unget is because unget returns the stream, but sungetc returns either the character that was pushed back, or EOF. This way we can tell if the function failed or not more easily.
我们使用 sungetc 而不是 istream 的 unget 的原因是因为 unget 返回流,但 sungetc 返回被推回的字符或 EOF。这样我们就可以更容易地判断函数是否失败。
If sungetc fails, one of the following will be true:
如果 sungetc 失败,以下情况之一将为真:
1) The stream is in an error state. 2) There are no characters to unget. 3) The stream doesn't support ungetting characters.
1) 流处于错误状态。2) 没有要取消的字符。3) 流不支持取消字符。
If sungetc succeeds, there will always be a character to read and test against the newline. If that character matches a newline, then the last read character was also a newline and we don't need to call ignore. If the character doesn't match, then a full line hasn't been read and we can safely call ignore without blocking.
如果 sungetc 成功,总会有一个字符来读取和测试换行符。如果该字符与换行符匹配,则最后读取的字符也是换行符,我们不需要调用 ignore。如果字符不匹配,那么整行还没有被读取,我们可以安全地调用 ignore 而不阻塞。
If the stream is in an error state, that's something the calling code has to deal with. If there are no characters to unget, then that's precisely what this solution is designed to properly handle. But, if the stream doesn't support ungetting characters, that's an issue. The ignore_line function will always fail to discard characters, so for those implementations that don't support ungetting characters, we can add a flag that forces an ignore. It's sometimes useful to know how many characters were ignored as well, so let's add that too and we have the final solution:
如果流处于错误状态,则这是调用代码必须处理的事情。如果没有要取消的字符,那么这正是该解决方案旨在正确处理的内容。但是,如果流不支持删除字符,那就是一个问题。ignore_line 函数总是无法丢弃字符,因此对于那些不支持删除字符的实现,我们可以添加一个强制忽略的标志。知道有多少字符被忽略有时也很有用,所以让我们也添加它,我们有最终的解决方案:
#include <ios>
#include <istream>
#include <limits>
template <typename CharT>
std::streamsize ignore_line ( std::basic_istream<CharT>& in, bool always_discard = false ) {
std::streamsize nread = 0;
if ( always_discard || ( in.rdbuf()->sungetc() != std::char_traits<CharT>::eof()
&& in.get() != in.widen ( '\n' ) ) )
{
// The stream is good, and we haven't
// read a full line yet, so clear it out
in.ignore ( std::numeric_limits<std::streamsize>::max(), in.widen ( '\n' ) );
nread = in.gcount(); }
return nread;
}
Just for good measure, I'll also include a manipulator that calls ignore_line and also a manipulator that uses ignore_line to pause the program. That way the unwashed masses can stop using system ( "PAUSE" ); and getch();:
为了更好地衡量,我还将包括一个调用 ignore_line 的操纵器,以及一个使用 ignore_line 暂停程序的操纵器。这样未清洗的群众可以停止使用系统(“暂停”);和 getch();:
class ignoreline {
bool _always_discard;
mutable std::streamsize _nread;
public:
ignoreline ( bool always_discard = false )
: _always_discard ( always_discard ), _nread ( 0 ) {}
std::streamsize gcount() const { return _nread;
}
template <typename CharT>
friend std::basic_istream<CharT>& operator>> ( std::basic_istream<CharT>& in, const ignoreline& manip )
{
manip._nread = ignore_line ( in, manip._always_discard );
return in;
}
};
class pause {
ignoreline _ignore;
public:
pause ( bool always_discard = false ) : _ignore ( always_discard ) {}
std::streamsize gcount()
const { return _ignore.gcount();
}
template <typename CharT>
friend std::basic_istream<CharT>& operator>> ( std::basic_istream<CharT>& in, const pause& manip )
{
if ( !( in>> manip._ignore ) )
in.clear();
std::cout<<"Press Enter to continue . . .";
return in.ignore();
}
};
Now all three cases behave identically:
现在所有三种情况的行为都相同:
int main()
{ std::cout<<"First input: ";
std::cin.get();
std::cout<<"Clearing cin.\n";
std::cin>> ignoreline();
std::cout<<"All done.\n";
std::cin>> pause();
}
And the moral of the story is: It's never as simple as it seems, writing portable code that does what you want is extremely difficult, and the iostream library is a huge mess.
这个故事的寓意是:它从来没有看起来那么简单,编写可移植的代码来做你想做的事情是极其困难的,而且 iostream 库是一个巨大的混乱。
NOTE: If you are a beginner forget everything and just understand there is a flushing problem and use cin
注意:如果您是初学者,请忘记一切,只知道存在冲洗问题并使用 cin
回答by Ken Wayne VanderLinde
Taking a look at the getlineprototype, you'll see that you need two things:
看看getline原型,你会发现你需要两件事:
- An
istream
object - A string to for the result
- (optionally) the "new line" delimiter (default is
'\n'
.
- 一个
istream
对象 - 结果的字符串
- (可选)“新行”分隔符(默认为
'\n'
.
In your case, it seems that the delimiter might be the default: '\n'
; if not, you can specify what character separates each value (maybe it's a space ' '
or something). The cin
stream would be you istream
object, and each of the properties of employees[count]
will serve as the second parameter. In summary, getline(cin, employees[count].name);
should do the trick.
根据你的情况,似乎是分隔符可能是默认的:'\n'
; 如果没有,您可以指定分隔每个值的字符(可能是空格' '
或其他东西)。该cin
流将是你istream
的对象,并且每个属性employees[count]
将作为第二个参数。总之,getline(cin, employees[count].name);
应该做到这一点。
回答by LihO
You can use getline function that takes input stream as first argument. It's prototype looks like this: basic_istream<...>& getline(basic_istream<...>& _Istr, basic_string<...>& _Str)
您可以使用将输入流作为第一个参数的 getline 函数。它的原型是这样的:basic_istream<...>& getline(basic_istream<...>& _Istr, basic_string<...>& _Str)
But then you have to think about that you are dealing with std::string
and parse it as a type that you actually need (char*
, int
, whatever):
但你要想想你正在处理std::string
,并解析它作为一个类型,你的实际需要(char*
,int
,等等):
#include <iostream>
#include <sstream>
#include <string>
using namespace std;
//...
for (int count=0; count < numberOfEmployees; count++)
{
string name, title, sSSnum, sSalary, s;
cout << "Name: ";
getline(cin, name);
employees[count].name = name.c_str();
cout << "Title: ";
getline(cin, title);
employees[count].title = name.c_str();
cout << "SSNum: ";
getline(cin, sSSnum);
istringstream is(sSSnum);
is >> employees[count].SSNum;
cout << "Salary: ";
getline(cin, sSalary);
is.clear();
is.str(sSalary);
is >> employees[count].Salary;
//...
}
回答by venkat
for (int count=0; count < numberOfEmployees; count++)
{
cout << "Name: ";
cin.getline (employees[count].name,100);
cout << "Title: ";
cin.getline (employees[count].title,100);
cout << "SSNum: ";
//error cin.getline (employees[count].SSNum);
cin>>employees[count].SSNum;
cout << "Salary: ";
// error cin.getline( employees[count].Salary);
cin>>employees[count].Salary;
cout << "Withholding Exemptions: ";
//error cin.getline (employees[count].Withholding_Exemptions);
cin>>employees[count]..Withholding_Exemptions;
}
回答by Rohit Vipin Mathews
istream& getline (char* s, streamsize n ); istream& getline (char* s, streamsize n, char delim ); Get line from stream
istream& getline (char* s, streamsize n ); istream& getline (char* s, streamsize n, char delim ); 从流中获取行
Extracts characters from the input sequence and stores them as a c-string into the array beginning at s.
从输入序列中提取字符并将它们作为 c 字符串存储到以 s 开始的数组中。
Characters are extracted until either (n - 1) characters have been extracted or the delimiting character is found (which is delim if this parameter is specified, or '\n' otherwise). The extraction also stops if the end of file is reached in the input sequence or if an error occurs during the input operation.
字符将被提取,直到 (n - 1) 个字符被提取或找到定界字符(如果指定了此参数,则为 delim,否则为 '\n')。如果在输入序列中到达文件末尾或在输入操作期间发生错误,提取也会停止。
If the delimiter is found, it is extracted and discarded, i.e. it is not stored and the next input operation will begin after it. If you don't want this character to be extracted, you can use member get instead.
如果找到分隔符,则将其提取并丢弃,即不存储它,并在它之后开始下一个输入操作。如果您不想提取此字符,则可以使用 member get 代替。
The ending null character that signals the end of a c-string is automatically appended to s after the data extracted.
在提取数据后,表示 c 字符串结束的结束空字符会自动附加到 s。
The number of characters read by this function can be obtained by calling to the member function gcount.
该函数读取的字符数可以通过调用成员函数gcount获得。
A global function with the same name exists in header . This global function provides a similar behavior, but with standard C++ string objects instead of c-strings: see getline (string).
header 中存在同名的全局函数。此全局函数提供了类似的行为,但使用标准 C++ 字符串对象而不是 c 字符串:请参阅 getline (string)。
Parameters s A pointer to an array of characters where the string is stored as a c-string. n Maximum number of characters to store (including the terminating null character). This is an integer value of type streamsize. If the function stops reading because this size is reached, the failbit internal flag is set. delim The delimiting character. The operation of extracting successive characters is stopped when this character is read. This parameter is optional, if not specified the function considers '\n' (a newline character) to be the delimiting character.
参数 s 指向字符数组的指针,其中字符串存储为 c 字符串。n 要存储的最大字符数(包括终止空字符)。这是一个 streamsize 类型的整数值。如果函数因为达到此大小而停止读取,则设置 failbit 内部标志。delim 分隔符。当读取到该字符时,停止提取连续字符的操作。此参数是可选的,如果未指定,函数会将 '\n'(换行符)视为分隔符。
Return Value The function returns *this.
返回值 该函数返回 *this。
MSDN EXAMPLE:
MSDN 示例:
// istream getline
#include <iostream>
using namespace std;
int main () {
char name[256], title[256];
cout << "Enter your name: ";
cin.getline (name,256);
cout << "Enter your favourite movie: ";
cin.getline (title,256);
cout << name << "'s favourite movie is " << title;
return 0;
}
And for your situation with structure object, u have to use the objectname.datamember to access objects data:
对于结构对象的情况,您必须使用 objectname.datamember 来访问对象数据:
for (int count=0; count < numberOfEmployees; count++)
{
cout << "Name: ";
cin.getline (employees[count].name,100);
cout << "Title: ";
cin.getline (employees[count].title,100);
cout << "SSNum: ";
cin.getline (employees[count].SSNum);
cout << "Salary: ";
cin.getline( employees[count].Salary);
cout << "Withholding Exemptions: ";
cin.getline (employees[count].Withholding_Exemptions);
}