How to read until EOF from cin in C++ - c++

I am coding a program that reads data directly from user input and was wondering how could I (without loops) read all data until EOF from standard input. I was considering using cin.get( input, '\0' ) but '\0' is not really the EOF character, that just reads until EOF or '\0', whichever comes first.
Or is using loops the only way to do it? If so, what is the best way?

The only way you can read a variable amount of data from stdin is using loops. I've always found that the std::getline() function works very well:
std::string line;
while (std::getline(std::cin, line))
{
std::cout << line << std::endl;
}
By default getline() reads until a newline. You can specify an alternative termination character, but EOF is not itself a character so you cannot simply make one call to getline().

Using loops:
#include <iostream>
using namespace std;
...
// numbers
int n;
while (cin >> n)
{
...
}
// lines
string line;
while (getline(cin, line))
{
...
}
// characters
char c;
while (cin.get(c))
{
...
}
resource

You can do it without explicit loops by using stream iterators. I'm sure that it uses some kind of loop internally.
#include <string>
#include <iostream>
#include <istream>
#include <ostream>
#include <iterator>
int main()
{
// don't skip the whitespace while reading
std::cin >> std::noskipws;
// use stream iterators to copy the stream to a string
std::istream_iterator<char> it(std::cin);
std::istream_iterator<char> end;
std::string results(it, end);
std::cout << results;
}

After researching KeithB's solution using std::istream_iterator, I discovered the std:istreambuf_iterator.
Test program to read all piped input into a string, then write it out again:
#include <iostream>
#include <iterator>
#include <string>
int main()
{
std::istreambuf_iterator<char> begin(std::cin), end;
std::string s(begin, end);
std::cout << s;
}

Probable simplest and generally efficient:
#include <iostream>
int main()
{
std::cout << std::cin.rdbuf();
}
If needed, use stream of other types like std::ostringstream as buffer instead of standard output stream here.

Sad side note: I decided to use C++ IO to be consistent with boost based code. From answers to this question I chose while (std::getline(std::cin, line)). Using g++ version 4.5.3 (-O3) in cygwin (mintty) i got 2 MB/s throughput. Microsoft Visual C++ 2010 (/O2) made it 40 MB/s for the same code.
After rewriting the IO to pure C while (fgets(buf, 100, stdin)) the throughput jumped to 90 MB/s in both tested compilers. That makes a difference for any input bigger than 10 MB...

You can use the std::istream::getline() (or preferably the version that works on std::string) function to get an entire line. Both have versions that allow you to specify the delimiter (end of line character). The default for the string version is '\n'.

while(std::cin) {
// do something
}

Wait, am I understanding you correctly? You're using cin for keyboard input, and you want to stop reading input when the user enters the EOF character? Why would the user ever type in the EOF character? Or did you mean you want to stop reading from a file at the EOF?
If you're actually trying to use cin to read an EOF character, then why not just specify the EOF as the delimiter?
// Needed headers: iostream
char buffer[256];
cin.get( buffer, '\x1A' );
If you mean to stop reading from a file at the EOF, then just use getline and once again specify the EOF as the delimiter.
// Needed headers: iostream, string, and fstream
string buffer;
ifstream fin;
fin.open("test.txt");
if(fin.is_open()) {
getline(fin,buffer,'\x1A');
fin.close();
}

One option is to a use a container, e.g.
std::vector<char> data;
and redirect all input into this collection until EOF is received, i.e.
std::copy(std::istream_iterator<char>(std::cin),
std::istream_iterator<char>(),
std::back_inserter(data));
However, the used container might need to reallocate memory too often, or you will end with a std::bad_alloc exception when your system gets out of memory. In order to solve these problems, you could reserve a fixed amount N of elements and process these amount of elements in isolation, i.e.
data.reserve(N);
while (/*some condition is met*/)
{
std::copy_n(std::istream_iterator<char>(std::cin),
N,
std::back_inserter(data));
/* process data */
data.clear();
}

Related

Strange things with c++ string input

#include <iostream>
#include <cstring>
using namespace std;
const int BUFFER_SIZE = 80;
void getstr(char* &str);
int main()
{
char* str;
while(true)
{
getstr(str);
if (!strlen(str))
break;
}
delete [] str;
return 0;
}
void getstr(char* &str)
{
char temp[BUFFER_SIZE];
cout<<"Enter a string(empty line to quit): ";
cin.get(temp, BUFFER_SIZE);
while(cin.get()!='\n')
continue;
str = new char [strlen(temp)+1];
strcpy(str, temp);
}
I have a string reading loop above and entering an empty line to terminate the loop doesn't work(after entering an empty line program stops responding to any input). But when I replace a loop in getstr with single cin.get() all works fine. What's wrong?
istream::get() sets failbit when empty string is read.
This makes cin.get() return EOF and this because you couldn't break the loop while(cin.get()!='\n').
You can use ios::clear() to clear failbit.
cin.get(temp, BUFFER_SIZE);
cin.clear(); // add this
while(cin.get()!='\n')
continue;
cin.get(char* s, size_t n) Extracts characters from the stream and stores them in s as a c-string, until either (n-1) characters have been extracted or the delimiting character is encountered: the delimiting character being either the newline character ('\n') or delim (if this argument is specified).
The delimiting character is not extracted from the input sequence if found and remains there as the next character to be extracted from the stream (see getline for an alternative that does discard the delimiting character).
A null character ('\0') is automatically appended to the written sequence if n is greater than zero, even if an empty string is extracted.
So here is the problem. cin.get() need to read at least 1 character. You can close stdin by pressing Ctrl+D and Enter, after that, your program will be finished.
And BTW, you are using new N times, but you have only 1 delete. You need to delete the previous buffer
If you are going to use C++, you should really use cin/cout in an objectively consistent manner. For example:
string name;
cout << "What is your name: ";
getline (cin, name);
cout << "Your name is: " << name;
What you are doing is kind of a C/C++ hybrid (char arrays in leu of string objects, but using std namespace).
Now, I know this isn't your question, but what you are doing right now is slightly unorthodox which makes answering your question a bit difficult without putting the code in to and editor and debugging it.
Given the c++11 tag, I assume that you really want C++ code. The great thing is that C++ simplifies this a lot.
#include <iostream>
#include <string>
int main()
{
std::string str;
while(std::getline(std::cin, str) && !str.empty())
{
// do stuff
}
return 0;
}

Streaming I/O in c++

I am trying to get this file stream program to work but when I run it all that happens is it outputs "Writing" instead of outputting the file. What am i doing wrong?
#include "stdafx.h"
#include <fstream>
#include <iostream>
using namespace std;
int main()
{
char str[10];
ifstream b_file ( "ioTest.txt" );
b_file>> str;
cout<< str <<"\n";
cin.get();
}
The standard input streams use whitespace as a delimiter for input. If you try extracting to a string, it will extract every character until a whitespace character is found. If you need the entire content of the file, here are a few options:
while (in >> word)
while (b_file >> word)
{
std::cout << word;
}
This method will iterate over each whitespace-separated tokens in the input stream.
std::getline()
while (std::getline(b_file, line))
{
std::cout << line;
}
std::getline() retrieves line-wise input, meaning it will extract every character until it reaches a delimiter. The delimiter by default is the newline but it can be specified as a third argument.
std::istream_iterator<T>
std::copy(std::istream_iterator<std::string>(b_file),
std::istream_iterator<std::string>(),
std::ostream_iterator<std::string>(std::cout, "\n"));
std::istream_iterator is a special-purpose stream iterator class designed to "iterate" over tokens of type T from an input stream.
rdbuf()
std::cout << b_file.rdbuf();
This is more low-level. An overload of std::ostream::operator<<() takes a stream buffer pointer as an argument, and it will extract characters directly from the buffer.

Getting input from file troubles C++

I've been trying to read some information in from a .txt file in C++ but it's not all working like I expect. Here is some example code:
#include <iostream>
#include <fstream>
using namespace std;
int main()
{
char words[255];
int value = 0;
ifstream input_stream("test.txt");
input_stream >> value;
input_stream.getline(words, 256);
cout << value << endl;
cout << words << endl;
}
And test.txt contains:
1234
WordOne WordTwo
What I expect is for the code to print the two lines contained in the text file, but instead I just get:
1234
I've been reading about getline and istream but can't seem to find any solutions so any help would be appreciated.
Thanks
The newline character remains in the input stream after the read of the integer:
// Always check result to ensure variables correctly assigned a value.
if (input_stream >> value)
{
}
Then, the call to getline() reads the newline character and stops, producing an empty string. To correct, consume the newline character before calling getline() (options include using getline() or ignore()).
Note there is a version std::getline() that accepts a std::string as its argument to avoid using a fixed sized array of char, which is used incorrectly in the posted code.
ifstream's getline method gathers input until one of two options is hit. Either a terminating character or the size passed in is reached. In your case, the newline terminator is encountered before the size is reached.
Use another getline to retrieve the second line of text.
Reference
The problem you are seeing is that the first newline after 1234 is not consumed by input_stream>>(int); so the next getline only reads to the end of that file.
This is a very constructed scenario, commonly found in schoolwork. The more common scenario when reading a textfile is to consider the entire file as linebased text.
In this case the more convenient
string line;
while( std::getline( input_stream, line ) ){
}
is appropriate, and way less error prone.
The textfile would commonly have a predefined format. Perhaps name = value lines, and are parsed as such after the line is read from the file.
Here is a somewhat corrected version of your original code:
#include <iostream>
#include <fstream>
using namespace std;
int main()
{
char words[256]; // was 255
int value = 0;
ifstream input_stream("test.txt");
input_stream >> value;
input_stream.ignore(); // skip '\n'
input_stream.getline(words, 256);
cout << value << endl;
cout << words << endl;
}
Also, I would advise you to use a string instead of a char[] and use the other getline function.

How to read the string into a file C++

i have a little problem on writing the string into a file,
How can i write the string into the file and able to view it as ascii text?
because i am able to do that when i set the default value for str but not when i enter a str data
Thanks.
#include <iostream>
#include <fstream>
#include <cstring>
using namespace std;
int main()
{
fstream out("G://Test.txt");
if(!out) {
cout << "Cannot open output file.\n";
return 1;
}
char str[200];
cout << "Enter Customers data seperate by tab\n";
cin >> str;
cin.ignore();
out.write(str, strlen(str));
out.seekp(0 ,ios::end);
out.close();
return 0;
}
Please use std::string:
#include <string>
std::string str;
std::getline(cin, str);
cout << str;
I'm not sure what the exact problem in your case was, but >> only reads up to the first separator (which is whitespace); getline will read the entire line.
Just note that >> operator will read 1 word.
std::string word;
std::cin >> word; // reads one space seporated word.
// Ignores any initial space. Then read
// into 'word' all character upto (but not including)
// the first space character (the space is gone.
// Note. Space => White Space (' ', '\t', '\v' etc...)
You're working at the wrong level of abstraction. Also, there is no need to seekp to the end of the file before closing the file.
You want to read a string and write a string. As Pavel Minaev has said, this is directly supported via std::string and std::fstream:
#include <iostream>
#include <fstream>
#include <string>
int main()
{
std::ofstream out("G:\\Test.txt");
if(!out) {
std::cout << "Cannot open output file.\n";
return 1;
}
std::cout << "Enter Customer's data seperated by tab\n";
std::string buffer;
std::getline(std::cin, buffer);
out << buffer;
return 0;
}
If you want to write C, use C. Otherwise, take advantage of the language you're using.
I can't believe no one found the problem. The problem was that you were using strlen on a string that wasn't terminated with a null character. strlen will keep iterating until it finds a zero-byte, and an incorrect string length might be returned (or the program might crash - it's Undefined Behavior, who knows?).
The answer is to zero-initialize your string:
char str[200] = {0};
Supplying your own string as the value of str works because those in-memory strings are null-terminated.

C++ cin Question

Okay, I was writing a simple C++ function to combine cin'd strings. I'm working on Linux at the moment, so I don't have the luxury of a simple "getline(cin, input)" command. Here's the code so far:
string getLine()
{
string dummy;
string retvalue;
do
{
cin << dummy;
retvalue += dummy;
} while
return retvalue;
}
What I want to know is this: is the prompt actually asking the user for input, or is it still reading from the buffer that was left over because of a space?
There is a getline defined for strings:
std::string line;
std::getline(std::cin, line);
I'm working on Linux at the moment, so I don't have the luxury of a simple "getline(cin, input)" command.
What's Linux got to do with it? getline is standard C++, except it's spelled cin.getline(input, size[, delimiter]).
Edit: Not deleting this because it's a useful reference, but AraK's post illustrating std::getline should be preferred for people who want a std::string. istream's getline works on a char * instead.
Yes. the prompt IS actually asking the user for input, but it is expecting a word rather than a line. That is possibly why it appeared space sensitive to you.
What you want, assuming you want to read more than one line, is this.
#include <iostream>
...
std::string sLine;
while(getline(std::cin, sLine)) {
// process sLine;
}
The code had a few other issues.
cin << dummy // this should have the >> operator
The variable should probably be called "word" not "dummy"
retvalue += dummy; // you would need to add spaces between words
} while // the while test should be some test for end of line
The loop in the question is closer to a word reader.
This would do for that objective.
#include <string>
#include <iostream>
#include <list>
...
void getStandardInput(std::list<std::string> & stringList) {
std::string word;
while (true) {
cin >> word;
if (cin.eof())
return;
stringList.push_back(word);
}
}
getline() is in the <string> header
I always forget that.