• 🏆 Texturing Contest #33 is OPEN! Contestants must re-texture a SD unit model found in-game (Warcraft 3 Classic), recreating the unit into a peaceful NPC version. 🔗Click here to enter!
  • It's time for the first HD Modeling Contest of 2024. Join the theme discussion for Hive's HD Modeling Contest #6! Click here to post your idea!

C++ Program Problem

Status
Not open for further replies.
Level 19
Joined
Oct 7, 2014
Messages
2,209
I got a task where we are required to make a program which uses decision making statements and constants/literals, so I made this program below.
The problem is I don't know how to identify if the value entered is an integer or a float.
C++:
#include <iostream>
using namespace std;

int main()
{  

int a,b,c;
cout << "enter 3 numbers";
cin >> a >> b >> c;

//Here, I wanted to check if a,b,c are integers
if (........)
  {
   if(a > b)
    {
     if( a > c)
      {
       cout << "a is largest number";
      }
     else
      {
       cout << "c is largest number";
      }
    }
   else
    {
     if( b> c)
      {
       cout << "b is largest number";
      }
     else
      {
       cout << "c is largest";
      }
    }
  }
else
   {
     cout << " a, b, c should be an integer";
   } 
  }

return 0;
}
 
Level 29
Joined
Jul 29, 2007
Messages
5,174
The << and >> stream operators are templates, meaning they take/give the type of variable or value you use.
Therefore, since you declared a, b, and c, to be integers, it will parse the input as an integer (whether it is a valid integer or not, that depends on your input - e.g. the user could input "abc" instead of a number, I don't remember what the standard library does in this case, because I haven't used C++ in years).
 

Dr Super Good

Spell Reviewer
Level 64
Joined
Jan 18, 2005
Messages
27,198
It seems the only approach is to try and fail a conversion.

C++:
#include <iostream>
#include <string>
using namespace std;

int main()
{
cout << "enter 3 numbers";

const int N_NUMBERS = 3;
int numbers [N_NUMBERS];
for (int i = 0 ; i < N_NUMBERS ; i+= 1 ) {
    cin >> numbers[i];
    if( cin.fail() ){
        cout << " a, b, c should be an integer";
        return 0;
    }
}

int max = 0;
for (int i = 1 ; i < N_NUMBERS ; i+= 1 )
    if( numbers[max] < numbers[i] )
        max = i;

const string varnames[] = { "a", "b", "c" };
cout << varnames[max];
cout << " is largest number";

return 0;
}
I have not syntax checked the above code so there may be errors. Additionally I am unsure about the constant string array initialization, that feature might only work with C++11 or newer compatible compilers. If it does not work then you will need to initialize the string array after declaring it.

Therefore, since you declared a, b, and c, to be integers, it will parse the input as an integer (whether it is a valid integer or not, that depends on your input - e.g. the user could input "abc" instead of a number, I don't remember what the standard library does in this case, because I haven't used C++ in years).
It will set the fail bit of the input stream if a conversion fails. For example if someone was to enter a floating point number when it is trying to parse an integer then the fail bit will be set. You can test the fail bit immediately after the operation.
 
This is a function I used in one of my projects. This function returns false if the string is empty OR doesn't start with '+' , '-' or a digit.
If the string didn't match the false condition above then the string is converted to a long (strtol). If successful, char* c will be 0 and the string will be a valid integer (or long which is just a 64 bit integer)
C++:
#include <stdlib.h> //strtol()
bool isInteger(const string &s)
{
   if(s.empty() || ((!isdigit(s[0])) && (s[0] != '-') && (s[0] != '+'))) return false ;

   char * c ;
   strtol(s.c_str(), &c, 10) ;

   return (*c == 0) ;
}
 
Last edited by a moderator:

Dr Super Good

Spell Reviewer
Level 64
Joined
Jan 18, 2005
Messages
27,198
When you enter any non-digit character it displays "c is the largest number" and I don't know why.
It is probably because it cannot parse an integer value from the stream so the variables are some default, nonsense/garbage value either defined by the compiler or by memory garbage.

The "int" type is always valid. Even if you fail to initialize it, it will still evaluate to a valid int value as nonsense as that value might be. As such you need other tests in parallel to keep track of if an int value is sensible or not. In my example this is done by testing if the stream failed after reading each int value. If it did fail then break out of the program since there is nothing logical left to do.


C++:
#include <iostream>
#include <string>
using namespace std;

int main()
{
// ask user for 3 numbers
cout << "enter 3 numbers";

// read in 3 numbers
const int N_NUMBERS = 3; // this is a numeric constant for how many numbers to read in
int numbers [N_NUMBERS]; // array to hold numbers, allows for easier processing
for (int i = 0 ; i < N_NUMBERS ; i+= 1 ) {
    // read in a number
    cin >> numbers[i];
    if( cin.fail() ){
        // number failed to read, print error and exit
        cout << " a, b, c should be an integer";
        return 0;
    }
}

// linear maximum search standard algorithm, search for maximum value index in the number array
int max = 0;
for (int i = 1 ; i < N_NUMBERS ; i+= 1 )
    if( numbers[max] < numbers[i] )
        max = i;

// some constant strings for which variable was the largest
const int N_VARNAMES = 3;
const string varnames[] = { "a", "b", "c" };

// print out which variable was the largest
if ( max < N_VARNAMES )
    // variable has been given a name
    cout << varnames[max];
else {
    // generate a name from the number
    cout << "variable ";
    cout << max;
}
cout << " is largest number";

// end program
return 0;
}

I don't know how to implement your code and because of that I got some compilation errors.
His function seems to try and parse a string as an integer and if it succeeds then it returns that it is an integer. This seems kind of inefficient seeing how the integer would then be parsed again later. It also seems the logic might not be correct since correct failure detection of strtol appears to be a combination of return value 0 and errno being set to an error value such as EINVAL or ERANGE.
 
Last edited by a moderator:
DSG's code is more modular, and definitely worth looking into when you revisit this task later, but can be difficult if you're still learning.

The main line to look at is this:
C++:
if (cin.fail())
{
    // do stuff when the user does not give you an integer
}

As Ghostwolf said, by doing cin << a << b << c, (with a, b, c as integers), you are letting the program know "I want integers!". So when the user does not input an integer, it will make it so "cin.fail()" is true.

So this is what the code will look like in the end:
C++:
#include <iostream>

using namespace std;

int main()
{
    int a, b, c;

    cout << "enter 3 numbers";
    cin >> a >> b >> c;

    if (cin.fail())
    {
        cout << "a, b, c should be an integer";
    }
    else
    {
        if (a > b)
        {
            if (a > c)
            {
                cout << "a is the largest integer";
            }
            else
            {
                cout << "c is the largest integer";
            }
        }
        else
        {
            if (b > c)
            {
                cout << "b is the largest integer";
            }
            else
            {
                cout << "c is the largest integer";
            }
        }
    }

    return 0;
}

Some interesting things worth noting:
  • Let's say the user enters "3", and then "a". What do you think will happen? Will it allow the user to enter one more number, and then notify the user that "a, b, c, should be an integer"? Or will it just show that message right away? As it turns out, it will show the message right away. cin will just stop receiving input as long as "cin.fail()" is true. If you want to reset it yourself, you'll have to use:
    C++:
    cin.clear()
  • "cin" is a stream, and it maintains certain "states". Just as a human has emotional states ("happy", "sad", "excited", etc.), a stream can have states of its own: "good" state -> no errors have happened; "fail" state -> a logical error has happened (e.g. trying to convert the input to an integer, when it isn't actually an integer); "bad" state -> read or writing error (e.g. something is actually preventing the stream from operating); and "eof" state -> end of file (used when reading files). Similar to how you use "cin.fail()", you can check all these states:
    C++:
    if (cin.fail()) { ... }
    if (cin.good()) { ... }
    if (cin.bad()) { ... }
    if (cin.eof()) { ... }
Don't stress too much about those notes yet. They're mostly just stuff you'll encounter later on. C++ is a rough language to learn where a lot of subtle information is contained within the documentation. Without a doubt, google and stackoverflow will become your best friends over the coming weeks. :D
 

Dr Super Good

Spell Reviewer
Level 64
Joined
Jan 18, 2005
Messages
27,198
you can check all these states:
Worth noting that cin.bad is a subset of cin.fail. As such it is pointless testing both bad and fail at the same time.

From what I have heard/read from other people is that istream and such API is slightly slower than C style stream API. This is micro optimization however and should only be concern if your application involves a lot of I/O (hundreds of megabytes to gigabytes). I would still recommend sticking to istream and ostream API for most general purpose IO needs.
 
Status
Not open for further replies.
Top