SSN

this program asks the user to input a SSN.
If the input is different than 10, an error message should raise.
If the second last digit is even, it belongs to a woman, or else, if odd,
it belongs to a man.

The program keeps crushing and I am not sure what the mistake is.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
  #include <iostream>
#include <string>

using namespace std;

int get_digit(int number)
{
	int second_last = number % 100 / 10;
	return second_last;
}

int main()
{
	char answer;
	do
	{

		string ssn;

		cout << "enter your SSN (10 digits)" << endl;
		getline(cin, ssn);
		if (ssn.length() != 10)
		{
			cout << "ERROR ! please enter a 10 digits SSN" << endl;
		}
		int n = stoi(ssn);  //convert string to integer
		if (get_digit(n) % 2 != 0)							//odd number belongs to a man	 
		{
			cout << "this SSN belongs to a man" << endl;
		}
		else if (get_digit(n) % 2 == 0)				//even number belongs  to  a woman
		{
			cout << "this SSN belongs to a woman" << endl;
		}

		cout << "try again (Y/N)?" << endl;
		cin >> answer;
	} while (answer == 'Y' || answer == 'y');


	return 0;
}
Last edited on
It's probably overflowing an int.

For what you are doing you only need to look at the penultimate char of the string, not convert the whole lot.
I see nothing wrong with line 18:

 
string ssn;

And I have no idea what your magic error code numbers mean.
I have edited the message, so there is no mention of line 18.
I convert the whole string in order to obtain the digit and find out if is odd or even.
So what should I do in order to make it work?
I am not sure what you mean by "overflowing an int"".
http://www.cplusplus.com/reference/string/stoi/
If the value read is out of the range of representable values by an int, an out_of_range exception is thrown.

the number is too big.
ascii is on par with int anyway. that is, the ascii for 0,2,4,... and 1,3,5 still works with %2 without any conversion, that is '4'%2 and 4%2 give the exact same result.

FYI. USA SSN is 9 digits, and there are some invalid ones like leading zero, but others as well.

int n = stoi(ssn); //convert string to integer not necessary, and get digit isn't necessary either. You may want to do them to get a handle on how that is done (may come in handy later) but here, its bloat.

basically... its ok to here, then take a look:
1
2
3
4
5
6
7
cout << "ERROR ! please enter a 10 digits SSN" << endl;
}
if(ssn[8]%2==0) 
   .. woman
else man
and resume as before from line 36...


Last edited on
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
#include <iostream>
// #include <climits>

// sanity check: unsigned long long is big enough to hold any 10-digit number
// not required as the standard guarantees this
// static_assert( std::numeric_limits< unsigned long long >::max() >= 9'999'999'999 ) ;


// checks if the input is a ten digit number
//     an alternative approach would be to accept numbers that have less than 10 digits
//     and treat hem as having leading zeroes. 
//     in that case, we should omit the number > 999'999'999 check 
bool is_ten_digit_number( unsigned long long number )
{
    return number > 999'999'999 && number < 100'000'000'000 ;
}

unsigned long long get_ssn()
{
    unsigned long long number ;
    std::cout << "enter your SSN (10 digits): " ;

    if( std::cin >> number ) // if the user entered a valid number
    {
        if( is_ten_digit_number(number) ) return number ; // 10 digit number, return it

        else std::cout << "error: " << number << " is not a ten digit integer. try again\n" ;
    }

    else
    {
        std::cout << "input error: you did not enter an integer. try again\n" ;

        // clean up the input. (you may want to ignore this nicety for now)
        std::cin.clear() ; // clear the failed state
        std::cin.ignore( 1000, '\n' ) ; // and extract and discard the bad input
    }

    // if we reach here, the input was not a 10 digit number
    return get_ssn() ; // try again
}

int second_last_digit( unsigned long long number )
{
    const int last_two_digits = number % 100 ;
    return last_two_digits / 10 ; // return the second last digit
}

void analyse_ssn( unsigned long long ssn )
{
    std::cout << "this SSN (" << ssn << ") belongs to a " ;

    const int digit = second_last_digit(ssn) ;

    if( digit%2 == 0 ) std::cout << "woman\n" ;
    else std::cout << "man\n" ;
}

char once_again() // return true if the user enters 'y' or 'Y'
{
    std::cout << "\nagain (y/n)? " ;
    char c ;
    std::cin >> c ;
    return c == 'y' || c == 'Y' ;
}

int main()
{
    std::cout << "note: this SSN analyser does not recognise a third gender\n\n" ;

    do
    {
        const unsigned long long ssn = get_ssn() ;
        analyse_ssn(ssn) ;
    }
    while( once_again() ) ;
} 
If you do any sort of string-to-integer conversion you will make it unnecessarily difficult to support SSNs starting with 0.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
#include <iostream>
#include <string>
using namespace std;

int main()
{
   const string numbers = "0123456789";
   const string evens   = "02468";

   char answer;

   do
   {
      string SSN;
      cout << "Enter your SSN (10 digits): ";
      getline(cin, SSN);
      if ( SSN.length() != 10 || SSN.find_first_not_of( numbers ) != string::npos )
      {
         cout << "ERROR! Invalid SSN\n";
      }
      else
      {
         cout << "This SSN belongs to a " << ( evens.find( SSN[8] ) == string::npos ? "man" : "woman" ) << '\n';
      }

      cout << "\nAnother go (Y/N)? ";
      cin >> answer;   cin.ignore( 1000, '\n' );
   } while ( answer == 'Y' || answer == 'y' );
}

Thank you everybody for your input.
I chose to go with jonnin's suggestion and added
those lines to my code.

I don't get errors stopping the command prompt from appearing, however
I get a windows with an error message
"Debug assertion failed".
Moreover, I obtain the following lines
"this SSN belongs to a man/woman"
even if the input is different than 10 digits.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
#include "pch.h"
#include <iostream>
#include <string>

using namespace std;

int main()
{
	char answer;
	do {

		string ssn;

		cout << "enter your SSN (10 digits)" << endl;
		getline(cin, ssn);
		if (ssn.length() != 10)
		{
			cout << "ERROR ! please enter a 10 digits SSN" << endl;
		}
		if (ssn[8] % 2 == 0)
		{
			cout << "this SSN belongs to a woman" << endl;
		}
		else
		{
			cout << " this SSN belongs to a man" << endl;
		}

		cout << "try again (Y/N)?" << endl;
		cin >> answer;
	} while (answer == 'Y' || answer == 'y');
		
	return 0;
}

Mmm, but look at the STRUCTURE of your code. There is no "else ..." corresponding to the error-checking block.
1
2
3
4
5
	if (ssn.length() != 10)
		{
			cout << "ERROR ! please enter a 10 digits SSN" << endl;
		}
          // But keeps going anyway, even if the above error occurs! 
I used a break statement after that line within the if loop, and it looks like it solves the problem, but the program is exited right away instead of going to the "try again" message.
How so?
A break statement will jump out of the immediately enclosing do loop, which in this case will take you to the end of the program.

Look at the STRUCTURE of your program:
1
2
3
4
5
6
7
8
      if (ssn.length() != 10)
      {
         cout << "ERROR ! please enter a 10 digits SSN" << endl;
      }
      else
      {
          // Put here what you do if it's a legitimate SSN
      }
this is my new code, but now I am dealing with a whole new problem:
if my input is not 10 digits, the message
"ERROR ! please enter a 10 digits SSN"
keeps being printed over and over again, together with
"try again?"
and there is no chance to input anything new.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
#include "pch.h"
#include <iostream>
#include <string>

using namespace std;

int main()
{
	char answer;
	do {

		string ssn;

		cout << "enter your SSN (10 digits)" << endl;
		getline(cin, ssn);
		if (ssn.length() != 10)
		{
			cout << "ERROR ! please enter a 10 digits SSN" << endl;
		}
		else if ((ssn.length() == 10) && (ssn[8] % 2 == 0))
		{
			cout << "this SSN belongs to a woman" << endl;
		}
		else if ((ssn.length() == 10) && (ssn[8] % 2 != 0))
		{
			cout << " this SSN belongs to a man" << endl;
		}

		cout << "try again (Y/N)?" << endl;
		cin >> answer;
	} while (answer == 'Y' || answer == 'y');
		
	return 0;
}
Maybe add some basic debug, like
1
2
3
cout << "ERROR ! please enter a 10 digits SSN" << endl;
cout << "Actual len=" << ssn.length() << endl;
cout << "+++" << ssn << "+++" << endl;

The second line will tell you how many characters you actually have.
The last line will tell you if there are any leading/trailing spaces or newlines in the string.
You are mixing getline(), which discards the newline character when it has read the line, and cin>>, which leaves it behind (so that the next getline() will pick up the blank remainder of the line).

You can clear the rest of the line up to and including the newline ('\n') character by changing your repeat prompt to:
cin >> answer; cin.ignore( 1000, '\n' );
There's nothing special about 1000 - anything bigger than the number of times you will erroneously press a key on the keyboard will do.
Topic archived. No new replies allowed.