Question:
I have made the following program that calculates inheritance based on the number of children:
#include <iostream>
using namespace std;
int leer_datoi()
{
int dato;
cin >> dato;
return dato;
}
double leer_datod()
{
double dato;
cin >> dato;
return dato;
}
void calcular_herencia()
{
double herencia, mayor;
int num_hijos;
do{
cout << "Ingrese el importe de la herencia:\t";
herencia=leer_dato_d();
cout << "\n";
if(herencia<=0)
cout << "ERROR. Ingrese una cantidad positiva\n" << endl;
} while(herencia<=0);
do{
cout << "Ingrese la cantidad de hijos:\t\t";
num_hijos=leer_dato_i();
cout << "\n";
if(num_hijos<=0)
cout << "ERROR. Ingrese una cantidad positiva\n" << endl;
} while(num_hijos<=0);
if(num_hijos<=4)
{
herencia=herencia/num_hijos;
cout << "La herencia para cada hijo es:\t\t" << herencia << "\n" << endl;
}
else
{
mayor=herencia/2;
herencia=mayor/(num_hijos-1);
cout << "La herencia para el hijo mayor es:\t" << mayor << "\n" << endl;
cout << "La herencia para el resto de hijos es:\t" << herencia << "\n" << endl;
}
}
int main()
{
calcular_herencia();
return 0;
}
Tried it and it works normal. Then, out of curiosity, I put a non-integer value when entering the number of children (let's say 4.5) and the program worked num_hijos
, which seems strange to me since the variable num_hijos
is of type integer.
My question is:
What is this about?
Answer:
When the program encounters this:
int dato;
cin >> dato;
Tries to read an integer from standard input. If the first character found is a numeric digit or the sign ( +
or -
), the stream
understand that it can start extracting an integer. When it ends? As it is reading an integer it will end when it can no longer extract any more digits, which happens, depending on your case, when it meets the point. At that moment it stops reading and returns the dato
number read up to that moment.
That is, before a 4.5
input, a 4
is stored in the dato
and the remainder .5
remains in the input buffer. You can check that this is true with the following example:
int main()
{
std::string cadena;
int variable;
std::cin >> variable >> cadena;
std::cout << variable << '\n' << cadena << '\n';
}
Before a type 4.5
input, the program prints the following:
4
.5
So, as you can see, the program does not do any magic but only gives you what you ask for.
We would have a different situation if the conversion was made once the data has been read. For example, imagine that instead of reading an integer, a double
is read and then an attempt is made to store that number in an integer. Something like that:
double temporal;
std::cin >> temporal;
int dato = static_cast<int>(temporal);
In this case cin
will read the entire number 4.5
and store it temporal
. The conversion to integer will cause a truncating of the decimals, so the decimal part ( .5
) will be lost and the dato
will finally store the integer part ( 4
).
Where is the difference in both cases? The result stored in dato
does not change, it is the same in both cases, however in this second example the input buffer remains clean, with no residues.
If we modify the example a bit:
int main()
{
int v1, v2;
std::cin >> v1 >> v2;
std::cout << v1 << '\n' << v2 << '\n';
}
And you enter, for example, 4.5 6
the program will print the following:
4
0
Where does that 0 come from? What happens is that after reading the first integer in the input buffer, the following residue is left: .5 6
. That starting point prevents you from correctly reading a whole second. When the reading error occurs, the cin
error flags are activated and the stream is blocked until said flags are reset.
This example shows how important it is to clear the input buffer before doing a read:
#include <iostream>
#include <limits>
int main()
{
int v1, v2;
if( !(std::cin >> v1) )
std::cin.clear();
std::cin.ignore(std::numeric_limits<int>::max(),'\n');
std::cin >> v2;
std::cout << v1 << '\n' << v2;
}
Where:
- The
clear
method clears the error flags from the stream . This action is only executed when the reading of the first integer fails (for example if you enter a character). - The
ignore
method allows you to discard characters from the stream . In this case, all the characters found up to the first line break will be discarded. -
numeric_limits
is a class that allows obtaining the limit values for each type of data (remember that the ranges are usually machine dependent). In this case you get the highest number that can be stored in a signed integer.