istream::unget() in C++ doesn't work as I thought - c++

unget isn't working the way I thought it would... Let me explain myself. As I think, unget takes the last character extracted in the stream and it puts it back in the stream (and ready to be extracted again). Internally, it's decreasing the pointer in the stream buffer (creating the sentry and all that stuff).
But, when I use two unget() one behind the other, it's behaviour get deeply strange. If write something like hello<bye, and I use < as a delimiter, if I use getline and later two ungets, it returns me hello, and no o<bye". This is my code:
#include <iostream>
#define MAX_CHARS 256
using namespace std;
int main(){
char cadena[MAX_CHARS];
cout << "Write something: ";
cin.getline(cadena, MAX_CHARS, '<');
cout << endl << "Your first word delimited by < is: " << cadena << endl;
cin.unget(); //Delimiter (removed by getline) is put back in the stream
cin.unget(); //!?
cin >> cadena;
cout << "Your phrase with 2 ungets done..." << cadena;
return 0;
}
Try with bye<hello, then cadena gets bye and not e<hello I thought that unget works with the last one character each time it's called, what the f*** is happening?

The problem you are observing isn't surprising at all. First off, note that ungetting characters may or may not be supported by the underlying stream buffer. Typically, at least one character of putback is supported. Whether this is actually true and if any more characters are supported is entirely up to the stream buffer.
What happens in your test program is simply that the second unget() fails, the stream goes into failure state (i.e., std::ios_base::failbit is set) and another attempt to read something just fails. The failed read leave the original buffer unchanged and since it isn't tested (as it should), it looks as if the same string was read twice.
The fundamental reason std::cin is likely to support only one character to be put back is that it is synchronized with stdin by default. As a result, std::cin doesn't do any buffer (causing it to be rather slow as well for that matter). There is a fair chance that you can get better results by no synchronizing with stdin:
std::ios_base::sync_with_stdio(false);
This will improve the performance and the likelihood of putting more characters being successful. There is still no guarantee that you can put multiple character (or even just one character) back. If you really need to put back character, you should consider using a filtering stream buffer which supports as many character puthback as you need. In general, tokenizing input doesn't require any characters of putback which is the basic reason that there is only mediocre support: since putback support is bad, you are best off using proper tokenizing which reduces the need to improve putback. Somewhat of a circular argument. Since you can always create your own stream buffer it isn't really harmful, though.

The actuall reason for this behaviour is related to the failbits of stream as explained in previous answer. I can provide a work around code that may help you in achieving the results you want.
#include <iostream>
#include <boost/iostreams/filtering_stream.hpp>
// compile using g++ -std=c++11 -lboost_iostreams
#define MAX_CHARS 256
using namespace std;
int main(){
boost::iostreams::filtering_istream cinn(std::cin,0,1);
char cadena[MAX_CHARS];
cout << "Write something: ";
cinn.getline(cadena, MAX_CHARS, '<');
cout << endl << "Your first word delimited by < is: " << cadena << endl;
cinn.unget(); //Delimiter (removed by getline) is put back in the stream
cinn.unget(); //!?
cinn >> cadena;
cout << "Your phrase with 2 ungets done..." << cadena;
return 0;
}

Related

How would one generalise `clearerr()` under C++?…

TL;DR
I am aware that if a program listens for EOF (e.g. ^D) as a sign to stop taking input, e.g. by relying on a conditional like while (std::cin) {...}, one needs to call cin.clear() before standard input can be read from again (readers who'd like to know more, see this table).
I recently learned that this is insufficient, and that the underlying C file descriptors, including stdin, need clearerr() to be run to forget EOF states.
Since clearerr() needs a C-style file descriptor, and C++ operates mainly with std::basic_streambufs and the like (e.g. cin), I want to generalise some code (see below) to run clearerr() on any streambuf's associated C-style file-descriptor, even if that may not be stdin.
EDITS (1&2):
I wonder if stdin is the only ever file-descriptor that behaves like this (needing clearerr() to run) ...?
If it isn't, then the following code should end the question of generalisation (idea pointed out by zkoza in their answer)
As zkoza pointed out in their comment below, stdin is the only file-descriptor that would, logically, ever need such treatment (i.e. clearerr()). Checking whether a given C++ stream is actually really attached to *std::cin.rdbuf() is all that is needed:
std::istream theStream /* some stream with some underlying streambuf */
if (theStream.rdbuf() == std::cin.rdbuf())
clearerr(stdin);
Background
I'm writing a tool in C++ where I need to get multiple lines of user input, twice.
I know there are multiple ways of getting multiline input (e.g. waiting for double-newlines), but I want to use EOF as the user's signal that they're done — not unlike when you gpg -s or -e.
After much consultation (here, here, and on cppreference.com), I decided to use... (and I quote the third):
[the] idiomatic C++ input loops such as [...]
while(std::getline(stream, string)){...}
Since these rely on std::basic_ios::operator bool to do their job, I ensured that cin.rdstate() was cleared between the first and second user-input instructions (using cin.clear()).
The gist of my code is as follows:
std::istream& getlines (std::basic_istream<char> &theStream,
std::vector<std::string> &stack) {
std::ios::iostate current_mask (theStream.exceptions());
theStream.exceptions(std::ios::badbit);
std::string &_temp (*new std::string);
while (theStream) {
if (std::getline(theStream, _temp))
stack.push_back(_temp); // I'd really like the input broken...
// ... into a stack of `\n`-terminated...
// ... strings each time
}
// If `eofbit` is set, clear it
// ... since std::basic_istream::operator bool needs `goodbit`
if (theStream.eof())
theStream.clear(theStream.rdstate()
& (std::ios::failbit | std::ios::badbit));
// Here the logical AND with
// ... (failbit OR badbit) unsets eofbit
// std::getline sets failbit if nothing was extracted
if (theStream.fail() && !stack.size()) {
throw std::ios::failure("No input recieved!");
}
else if (theStream.fail() && stack.size()) {
theStream.clear(theStream.rdstate() & std::ios::badbit);
clearerr(stdin); // 👈 the part which I want to generalise
}
delete &_temp;
theStream.exceptions(current_mask);
return theStream;
}
This does what you need:
#include <iostream>
int main()
{
std::cin.sync_with_stdio(true);
char c = '1', d = '1';
std::cout << "Enter a char: \n";
std::cin >> c;
std::cout << (int)c << "\n";
std::cout << std::cin.eof() << "\n";
std::cin.clear();
clearerr(stdin);
std::cout << std::cin.eof() << "\n";
std::cout << "Enter another char: \n";
std::cin >> d;
std::cout << (int)d << "\n";
std::cout << std::cin.eof() << "\n";
}
It works because C++'s std::cin is tied, by default, with C's stdin (so, the first line is actually not needed). You have to modify your code to check if the stream is std::cin and if so, perform clearerr(stdin);
EDIT:
Actually, sync_with_stdio ensures only synchronization between the C and C++ interfaces, but internally they work on the same file descriptors and this may be why clearerr(stdin); works whether or not the interfaces are tied by sync_with_stdio
EDIT2: Does these answer your problem? Getting a FILE* from a std::fstream
https://www.ginac.de/~kreckel/fileno/ ?

What's the difference between read, readsome, get, and getline?

What is the difference between these functions. When I use them they all do the same thing. For example all three calls return "hello":
#include <iostream>
#include <sstream>
int main()
{
stringstream ss("hello");
char x[10] = {0};
ss.read(x, sizeof(x)); // #1
std::cout << x << std::endl;
ss.clear();
ss.seekg(0, ss.beg);
ss.readsome(x, sizeof(x)); // #2
std::cout << x << std::endl;
ss.clear();
ss.seekg(0, ss.beg);
ss.get(x, sizeof(x)); // #3
std::cout << x;
ss.clear();
ss.seekg(0, ss.beg);
ss.getline(x, sizeof(x)); // #4
std::cout << x << std:endl;
}
get and getline are quite similar, when get is called with parameters ( char_type* s, std::streamsize count ). However, get reads from the stream until a delimiter is found, and then leaves it there. getline by comparison will pull the delimiter off the stream, but then drop it. It won't be added to the buffer it fills.
get looks for \n, and when a specific number of characters is provided in an argument (say, count) it will read up to count - 1 characters before stopping. read will pull in all count of them.
You could envisage read as being an appropriate action on a binary datasource, reading a specific number of bytes. get would be more appropriate on a text stream, when you're reading into a string that you'd like null-terminated, and where things like newlines have useful syntactic meanings splitting up text.
readsome only returns characters that are immediately available in the underlying buffer, something which is a bit nebulous and implementation specific. This probably includes characters returned to the stream using putback, for example. The fact that you can't see the difference between read and readsome just shows that the two might share an implementation on the particular stream type and library you are using.
I've observed the difference between read() and readsome() on a flash filing system.
The underlying stream reads 8k blocks and the read method will go for the next block to satisfy the caller, whereas the readsome method is allowed to return less than the request in order to avoid spending time fetching the next block.
The main difference between get() and getline() is that get() leaves the newline character in the input stream, making it the first character seen by the next input operation, whereas getline() extracts and discards the newline character from the input stream.

C++ Press Enter to Terminate Program [duplicate]

This question already has answers here:
Cin.Ignore() is not working
(4 answers)
Closed 9 years ago.
I am writing a C++ program and I need to program to end/terminate after the user hits enter.
This is what I have:
cout << "Press Enter to End" << endl;
cin.ignore(); //ends after the user hits enter
return 0;
But it doesn't work. Any advice?
I sense that you had some formatted input earlier in your program, i.e., it looks something like this:
std::cin >> value;
do_something(value);
std::cout << "press enter to end\n";
std::cin.ignore();
If that is the case, you have some character in the input buffer from the time you entered value. For example, there can be a '\n' but it can be any odd other characters, too. This character will be read when the program encounters std::cin.ignore().
What you probably want to is to get rid of the characters currently known to be in the buffer. This isn't quite what would be done as this can still miss characters which are already entered but not, yet, transferred but there is no portable approach to clear all potential characters (it is normally not a problem because hardly any user interface depends on character input from a terminal).
To ignore the characters which are known to be present you need to start off by breaking the connection between <stdio.h> and IOStreams using std::ios_base::sync_with_stdio() and later consume the known characters entered after your last read, e.g.,
#include <iostream>
int main()
{
std::ios_base::sync_with_stdio(false);
int x;
std::cin >> x;
std::cin.ignore(std::cin.rdbuf()->in_avail());
std::cout << "press enter\n";
std::cin.ignore();
}
The odd call to sync_with_stdio() is necessary to have the IOStreams actually buffer the characters received from the system rather than reading characters individually. As a nice side effect it dramatically improves the performance of using std:cin, std::cout, and the other standard stream objects.
maybe add system("pause") in the end of code; (include first). I guess you want enter to close termination.

Can't get ios::beg to go back to the beginning of the file

It always seems to be the things that should be no problem that cause problems for me. I don't get it. :/
So I'm trying to make sure that I understand how to manipulate text files. I've got two files, "infile.txt" and "outfile.txt". "infile.txt" has six numbers in it and nothing else. Here is the code I used to manipulate the files.
#include<fstream>
using std::ifstream;
using std::ofstream;
using std::fstream;
using std::endl;
using std::ios;
int main()
{
ifstream inStream;
ofstream outStream;//create streams
inStream.open("infile.txt", ios::in | ios::out);
outStream.open("outfile.txt");//attach files
int first, second, third;
inStream >> first >> second >> third;
outStream << "The sum of the first 3 nums is " << (first+second+third) << endl;
//make two operations on the 6 numbers
inStream >> first >> second >> third;
outStream << "The sum of the second 3 nums is " << (first+second+third) << endl;
inStream.seekg(0); //4 different ways to force the program to go back to the beginning of the file
//2. inStream.seekg(0, ios::beg);
//3. inStream.seekg(0, inStream.beg);
//4. inStream.close(); inStream.open("infile.txt");
//I have tried all four of these lines and only #4 works.
//There has got to be a more natural option than just
//closing and reopening the file. Right?
inStream >> first >> second >> third;
outStream << "And again, the sum of the first 3 nums is " << (first+second+third) << endl;
inStream.close();
outStream.close();
return 0;
}
Maybe I don't understand quite how the stream works, but I've seen a few sources that said that seekg(0) should move the index back to the start of the file. Instead, this is what I get out of it.
The sum of the first 3 nums is 8
The sum of the second 3 nums is 14
And again, the sum of the first 3 nums is 14
It went back, but not nearly in the way I would have hoped. Any idea why this happened? Why did my first three attempts fail?
As Bo Persson states, it may be because your input has
encountered end of file; it shouldn't, because in C++, a text
file is defined as being terminated by a '\n', but practically
speaking, if you're working under Windows, a lot of ways of
generating a file will omit this final '\n'—although it
is formally required, practical considerations will mean that
you'll make sure that it works even if the final '\n' is
missing. And I can't think of any other reason off hand why the
seekg's wouldn't work. inStream.seekg( 0 ) is, of course,
undefined behavior, but in practice, it will work pretty much
everywhere. inStream.seekg( 0, ios::beg ) is guaranteed to
work if inStream.good(), and is, IMHO, preferable to the
first form. (The single argument form of seekg is normally
only used with the results of a tellg as an argument.) And of
course, it only works if the actual input source supports
seeking: it won't work if you're reading from a keyboard or
a pipe (but presumably, "infile.txt" is neither).
In general, you should check the status of inStream after each
read, before using the results. But if the only problem is that
the file doesn't end with '\n', it's probable that the status
will be OK (!fail()) after the final read, even if you've
encountered end of file. In which case, you'll need clear()
anyway.
Note that the above comments are valid for C++-03 and precedent.
C++11 has changed the specification of the single argument form
of seekg, and requires it to reset eofbit before anything
else. (Why is this change only for the single argument form of
seekg, and not the two argument form? Oversight?)
The second input reaches end-of-file for the stream. That state sticks until you call inStream.clear() to clear its state (in addition to the seek).
With a C++11 compliant compiler, option 4 should also work as close and reopen will now clear the previous state. Older compilers might not do that.
Try:
inStream.seekg(0, ios_base::beg);

C instruction is being reordered when cin cout and gets is used consecutively

Does anyone knows why C instruction is being reordered when cin cout and gets is used consecutively here?
I am using Dev-C++ 4.9.9.2.
#include<iostream>
using namespace std;
int main(){
char a[10],b;
for(;;){
cout<<"\ncin>>b:";
cin>>b;
cout<<"gets(a):";
gets(a);
cout<<"cout<<a<<b:"<<a<<" "<<b<<"\n\n";
}
}
I got an output like:
cin>>b:132
gets(a):cout<<a<<b:32 1
cin>>b:465
gets(a):cout<<a<<b:65 4
cin>>b:312242
gets(a):cout<<a<<b:12242 3
cin>>b:1
gets(a):cout<<a<<b: 1
cin>>b:
It seemed like some input for cin was passed in gets.. and it also appears that instructions were reordered like:
cin>>b;
gets(a);
cout<<"gets(a):";
instead of,
cin>>b;
cout<<"gets(a):";
gets(a);
cin>>b read just a character, leaving the rest of the input to be read by later input operation. So gets sill has something to read and don't block.
At the first cin >> b, there is no input available. You enter '132\n' (input from terminal is usually made line by line) in a buffer and just get the 1 out of it. gets reads the next characters 32 and the \n which terminates gets. It doesn't need to read something more from the terminal.
Nothing has been re-ordered.
your input from keyboard has been send only when you pressed enter. At that time, there have been enough data to execute the cin<<b, the following cout, then to complete the gets(a).
In others words, the execution of cin<<b is suspended to the reception of a char. But that char is not send to the program until you pressed 'Enter' (this is because of your terminal settings). When you press 'Enter', the first char is received by cin<<b and the remaining is buffered. cout executes, and when it is the turn of gets(a), the buffer delivers the remaining chars included the carriage return, so gets(a) completes as well, with the data you entered to complete the cin<<b instruction.
Try to simply press enter for the cin<<b to complete, then you'll see the cout, and then you will have the gets(a) waiting for your inputs.
While not really answering your question...
The idiomatic way in C++ would rather be to use getline. It's an accident of history that does not make it part of the iostream interface directly, but it really is the function to use for inputs.
Shameless plug from the website:
// getline with strings
#include <iostream>
#include <string>
int main () {
std::string str;
std::cout << "Please enter full name: ";
getline (std::cin,str);
std::cout << "Thank you, " << str << ".\n";
}
The main advantage of getline, in this version, is that it reads up until it encounters a line-ending character.
You can specify your own set of "line-ending" characters in the overload accepting a third parameter, to make it stop on commas or colons, for example.
The code isn't reordered, but std::cout is buffered so the string doesn't appear immediately on your display. Therefore gets(a) will be executed with the output still in the buffer.
You can add a <<flush after the output string to make cout flush it's buffer.
When you use std::cin, it knows how to tell std::cout to flush the buffer before the input starts, so you don't have to.