How to read aloud c++ expressions with the input/output operators? - c++

I feel pretty stupid, but I'm just starting to learn c++ after coming from other languagues, and I cannot for the life of me comprehend statements that use "<<" and ">>". I know it is simple, but it confuses me every time.
The book I'm using made a really good recommendation to read const declarations from right to left. Is there any similar method for "<<" and ">>"?

i like to say "gets".
cout << "some expression = " << expr << endl;
i'd say that as "cout gets some expression, gets expr, gets endull." similarly if you're reading from a stream, it's your variable that "gets" a value from the input...

On the phone, back when I was a consultant frequently needing to "read aloud" C++ code to clients' employees on the phone, I (explaining once or twice, then they got it) read "input" operator >> as "absorb" and "output" operator << as "emit". "get" and "put" would work just as well if they didn't conflict with alas-too-common other uses. But that doesn't seem to have much to do with right-to-left vs left-to-right, just with your Q's title about "reading aloud" -- "cin absorb x" or "essteedee cout emit blach emit essteedee endl" kinds of "reading code aloud" (e.g. on the phone)!-)

I typically read them from left to right, like so:
cout << setw(6) << val << endl;
"Send to cout, with a width of 6, the contents of val, and then end the line and flush."
or
cin >> val;
"Get from cin the contents of val."
It does take a little bit of special consideration in that you can't just say specific words for each token.

To understand C++, you have to understand that C++ has many of the most powerful tools to build abstractions. cout is nothing but a stream. So, it is very acceptable to mimic the concept of stream.
For example,
std::cout << "hey"; // '<<' is something like the direction of the `data`
throws things in the stream with the same syntax and conventions, infact there is only one syntax for all types.
Also,
std::cin >> number;
extracts the next value of the type specified by number and put it in number.
It just make sense when you think about streams in C++. You can see this in most modern C++ libraries, for example with Boost you can do this:
boost::filesystem::path mypath;
....
mypath = mypath/filename;
The division operator is replaced with '/' or '\' depending on the system you are targeting :)

I never thought too much about it but I suppose you could say "Streams to" or "Streams from" eg.
cout << mysting << endl;
"cout streams from mystring streams from endline"
cin >> myvalue;
"cin streams to myvalue"
I just made that up but it makes sense to me.

This is easy enough the object that the symbol is pointing to on the receiving end. So:
cout << "Enter First Name: ";
cin >> FirstName;
in this code, cout in usually stdout and is "receiving" the characters "Enter First Name", FirstName which is presumably a variable is "receiving" the data from cin which is probably stdin.

A simple way to distinguish the two is like so.
cout << "Some fancy string...";
In this example your are taking a string and sending it to the world (monitor).
cin >> x;
In that one you take an value from the world (keyboard) and save the it into x.
Hence the direction Value >> X.

Related

C++ Why diff EOF checks recommended for text vs numeric?

My textbook recommends using the member accessor method iStreamVar.eof() when dealing with textual data and while (iStreamVar) when dealing with numeric data.
Can someone please explain why it would matter?
Quote from book:
Using the function eof to determine the end-of-file status works best if the input is text. The earlier method of determining the end-of-file status works best if the input consists of numeric data.
That is the only thing mentioned on the topic. After this, it just explains how the process works.
Which method you use for determining the end of data depends on how you use it. My guess is, both methods which your textbook mentions are used wrong, so they fail in different situations. That's why it recommends using different methods in different situations.
The correct method is not trivial, and it depends on how important error resilience is for you.
If you want to read a space-delimited stream with numbers in it, and you are sure the file contains no errors, the code is simplest:
int value;
while (iStreamVar >> value)
{
...
}
Note that it's not any of the two original options.
If your file contains space-delimited textual data, and you are sure there are no errors, use the same code (but declare the temporary variable as string instead of int).
If you want to detect and recover from errors, use more elaborate code. But I cannot recommend you any specific code structure - it depends on what exactly you want to do in case of errors. Also:
Are text records delimited by space or newline?
What if the input text-file contains an empty line?
Numbers - floating-point or not?
Numbers - if there is a stray character like a among number data, what to do?
So there is no single correct recipe for doing proper input with error resilience.
Unless there is something significant in the context that isn't shown in the question, that quote is nonsense.
The way to read from a file and check for success is to read from the file:
int data;
if (std::cin >> data)
std::cout << "read succeeded, value is " << data << '\n';
std::string data;
if (std::cin >> data)
std::cout << "read succeeded, value is " << data << '\n';
std::string data;
if (std::getline(std::cin, data)
std::cout << "read succeeded, value is " << data << '\n';
If an attempted read fails you can call .eof() to find out whether the failure was because the input was at the end of the file. Contrary to what some beginners expect (and what some languages do), if .eof() returns false it does not mean that there is data remaining in the input stream. The stream might be at the end of the file after a successful read consumed the remaining input. .eof() will return false, but the next attempted read will fail, and after that, .eof() will return true.
std::stringstream input("1234");
int data;
input >> data; // succeeds
std::cout << input.eof() << '\n'; // outputs 0, no failure
input >> data; // fails, no more input
std::cout << input.eof() << '\n'; // outputs 1, failed because at end of file

C++ reading a file into a struct

Using fstreams I have a file opened that contains numerous lines. Each contiguos set of 4 lines are such that: the first line is an int, the second and third are strings and fourth is a double. This sequence continues till EOF.
I'm attempting to load these lines into a struct array:
struct Library {
int id;
string title;
string artist;
double price;
};
and the code I'm trying to implement to load data into the struct is this:
const int LIMIT = 10
Library database[LIMIT];
ifstream file;
file.open("list.txt");
if(file) {
while(!(file.eof()) && counter < LIMIT) {
file >> database[counter].id;
getline(file, database[counter].title;
getline(file, database[counter].artist;
file >> database[counter].price;
}
} else {
...
}
// Using the following to debug output
for(int i = 0; i < counter; i++) {
cout << "ID: " << database[i].id << endl
<< "Title: " << database[i].title << endl
<< "Artist: " << database[i].artist << endl
<< "Price: " << database[i].price << endl
<< "-----------------------" << endl;
}
The file I'm trying to throw at this thing is
1234
Never Gonna Give You Up
Rick Astley
4.5
42
Thriller
Michael Jackson
32.1
The problem I'm having here is that between reading the id and title using file >> ... and getline(...) is that somewhere a newline bite is being introduced screwing up the output, which displays this monstrosity...
ID: 1234
Title:
Artist: Never Gonna Give You Up
Price: 0
--------------------
ID: 0
Title:
Artist:
Price: 0
--------------------
The solution is probably the most basic of solutions, but mainly because I can't figure out exactly what is going on with the newline bite I can't combobulate a phrase to shove into google and do my stuff there, and I'm at the stage where I've been looking at a problem so long, basic knowledge isn't working properly - such as how to handle basic input streams.
Any form of help would be much appreciated! Thanks in advance :)
This happens because the >> operator for the input stream only grabs part of a line, and does not always grab the newline character at the end of the line. When followed by a call to getline, the getline will grab the rest of the line previously parsed, not the line after it. There are a few ways to solve this: you can clear the buffer from the input stream after each read, or you can simply get all your input from getline and just parse the resulting strings into an integer or a double when you need to with calls to stoi or stod.
As a side note, you don't want to detect the end of your file the way you presently are. See why is eof considered wrong inside a loop condition?
You can solve this problem by adding:
fflush(file);
everytime before you use getline(file, ...). Basically this will clear the input buffer before you use the getline() function. And fflush() is declared in the cstdio library.
file >> database[counter].id;
will read, in this case, a whitespace separated sequence of characters that is interpreted as an int. The newline is considered whitespace. You should now be sitting on that newline character, thus the getline() will read nothing -- successfully -- and increment the file position just past that.
You may be better off using getline() for each line and then separately interpreting the lines from the reading. For example, the first line read could be interpreted with a subsequent std::stoi() to get the integer representation from the string.

C++ skipping the new line key?

I am trying to get the user to input some data and then storing it in a structure, however I am having troubles knowing which function I should use and what's the difference? cin or getline()? Either function I use, it seems like it takes in the '\n' key and makes my program crash, but I am not 100% if that's the problem... Since it keeps crashing.
I've played around with both of them and here is what I have.
string temp;
int id;
cout << endl << "Full name (last, first): ";
cin >> temp;
cin.ignore(1, '\n');
myData[fileSize] = parseName(temp);
cout << endl << "ID: ";
cin >> id;
myData[fileSize].id = id;
cout << endl << "Address: ";
cin >> temp;
temp.copy(myData[fileSize].address, temp.length(), 0);
The variable fileSize is just which element the array is currently at and the function parseName splits the name into last and first.
I been reading on a couple of functions like, cin.ignore() and noskipws, but not sure how to use them. By the way, the way the user should input the data is "last, first", with a comma and white space after (this is what the parsing function is looking for).
Also I am not sure if the address section is the best way to do this, I have the structure myData.address to be a character array, because I don't know how to work with strings. I am still not confident with C++. Thanks for any help.
EDIT: If I comment out the ID and Address parts, the program loops itself 6 times saying I have an invalid entry (which is part of main), so it reads 6 or 7 keys after I press enter.
If I leave everything the way it is, this is what I get.
Full name (last, first): terminate called after throwing an instance of 'std::ou
t_of_range'
what(): basic_string::copy
This application has requested the Runtime to terminate it in an unusual way.
Please contact the application's support team for more information.
Process returned 3 (0x3) execution time : 4.328 s
Press any key to continue.
You should use cin.getline() instead for this case, and the cin.ignore is not necessary.
Here is an examination of the two methods - std::cin.getline( ) vs. std::cin
Also, check your parseName function and try testing it in isolation without any user I/O.

C++ - cin.get(array,int) not reading first char

I'm new to C++ and I'm trying some exercises. The first one I wanted to do already got me in trouble. The goal of the exercise is to reverse the string you input. This is easy. But when in try to limit the amount of characters with cin.get(array,int) it removes the first character.
Code:
char voornaam[7];
cin >> voornaam;
cin.get(voornaam,7);
cout << voornaam[6] << voornaam[5] << voornaam[4] << voornaam[3] << voornaam[2] << voornaam[1] << voornaam[0] << endl;
This is the code. So this should normally work but when I try it for example with Sander, it outputs 'redna' and then terminates.
Any thoughts on how to fix this. I would like a solution with cin.get(array,int) and not with an other function of cin.
Thanks.
Well, this is funny. At first instance everything is fine. But with one minor thing. Notice
cin >> voornaam
followed by
cin.get(voornaam,7)
What happens here is, when first prompt comes, you enter Sander.
Hence, voornaam[0] = 'S' , voornaam[1] = 'a' and so on. And you press enter. cin.get(voornaam, 7) takes this as \0. So, your voornaam looks something like
voornaam[0] = '\0'
voornaam[1] = 'a'
voornaam[2] = 'n'
and so on.
And when you reverse it, you get "redna". So, do not use, cin twice, or enter full string twice to get the correct result.

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

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;
}