Validating Social Security integers. Help!!!!!!!!!

R

rlueneberg

I am having trouble validating a social security number. If I use
valid integers, for example 3944 or 663949956, the code skips to loop2
and I don't have problems. If I use alpha characters, for example
"abcde" the code runs through loop1 and everything works perfectly.

The problem starts when I type in for example "44abcde". Immediately,
code enters in an infinite loop. If I type "abcde44" it works
normally. I am desperately looking for help since this is an
assignment and I am still learning the language.


int main()
{
HourlyPay p;
int SSN=0;
cout << "Enter Social Security: " << endl;
cin >> SSN;
// loop 1
while (cin.fail())
{
cin.clear();
cin.ignore(100, '\n'); // skip 100 chars or to next end of line
whichever comes first
cout << "Invalid Social Security Number!!!!\n";
cout << "Try Again: " << endl;
cin >> SSN;
}
// loop 2
while(p.getSSN(SSN)=="invalid")
{
cin.clear();
cout << "Invalid Social Security Number!!!!";
cin >> SSN;
}
cout << p.getSSN(SSN);

system("PAUSE");
return 0;
}

The other problem that I am having is if I type more than 100 alpha
chars it display another line repeating the same previous error
message.


Thank you

Rod
 
O

osmium

I am having trouble validating a social security number. If I use
valid integers, for example 3944 or 663949956, the code skips to loop2
and I don't have problems. If I use alpha characters, for example
"abcde" the code runs through loop1 and everything works perfectly.

The problem starts when I type in for example "44abcde". Immediately,
code enters in an infinite loop. If I type "abcde44" it works
normally. I am desperately looking for help since this is an
assignment and I am still learning the language.


This did not compile, did it?
int main()
{
HourlyPay p;

we don't know what the type HourlyPay is
int SSN=0;
cout << "Enter Social Security: " << endl;
cin >> SSN;
// loop 1
while (cin.fail())
{
cin.clear();
cin.ignore(100, '\n'); // skip 100 chars or to next end of line
whichever comes first
cout << "Invalid Social Security Number!!!!\n";
cout << "Try Again: " << endl;
cin >> SSN;
}
// loop 2
while(p.getSSN(SSN)=="invalid")

we can't see the code for the function (apparently) getSSN
But the construct looks fishy. Functions don't return C style strings.
{
cin.clear();
cout << "Invalid Social Security Number!!!!";
cin >> SSN;
}
cout << p.getSSN(SSN);

system("PAUSE");
return 0;
}

The other problem that I am having is if I type more than 100 alpha
chars it display another line repeating the same previous error
message.

First things first.

The usual way of validating data entry is to read an entire line as a
string, then validate the individual fields. If I were thee user and given
that prompt I would type <ddd dd dddd> which is not a number as far as C++
is concerned, it is three numbers
 
D

Default User

osmium said:
we can't see the code for the function (apparently) getSSN
But the construct looks fishy. Functions don't return C style
strings.


They can. That comparison wouldn't be advised in that case, of course.
As you say in the part I snipped, the program is incomplete so we don't
know what is going on.




Brian
 
J

James Kanze

This did not compile, did it?

Obviously, he trimmed the includes.
we don't know what the type HourlyPay is

Which probably doesn't matter.
we can't see the code for the function (apparently) getSSN
But the construct looks fishy. Functions don't return C style strings.

But you can compare an std::string with a C style string without
any problem.

I'm just guessing, but if this is the loop that doesn't
terminate, it's probably normal. Given "44abc" the first read
succeeds, writing 44 to SSN, and leaving the stream positionned
at "abc". And I rather suspect that 44 is not a valid social
security number, so you enter this loop. The read in it fails,
because "abc" is NOT a valid int, so SSN remains unchanged.
First things first.
The usual way of validating data entry is to read an entire line as a
string, then validate the individual fields. If I were thee user and given
that prompt I would type <ddd dd dddd> which is not a number as far as C++
is concerned, it is three numbers

Agreed. But note that the loop is probably still a little
tricky; you want to loop on invalid input, but if you don't
break the loop on a real end of file, it's likely to end up
infinite as well. Something like the following would probably
do the trick, however:

std::string line ;
while ( std::getline( std::in, line ) && ! isValidSSN( line ) ) {
std::cout << "Try again: " ;
std::cout.flush() ;
}
if ( ! std::in ) {
std::cerr << "Unexpected EOF (or other input error)" <<
std::endl ;
} else {
// Whatever processing is needed...
}

Also, as a general rule, I'd probably keep the social security
number in a string, rather than an int, to begin with.
Normalizing the format, of course. (As a simple first guess,
isValidSSN would verify that the line only contained digits and
white space, and contained the correct number of digits.
Normalizing the format would only entail removing any white
space. A total of about four or five lines of code.)
 
R

rlueneberg

Yes it does Compile. The code is still under work but I am posting it
in full. I liked the last suggestion to keep SSN in string. I believe
this will avoid a lot of headaches with int validation.

#include <iostream>
#include <string>
#include "stdafx.h"
#include <ctype.h>

using namespace std;

class Employee
{
protected:
// Full Name
string name;
// Employee Number
char EmployeeID[5];
// Social Security Number
string SocialSecurity;
// Hire Date
string HireDate;
public:
// constructor
Employee() {}

string getSSN(int MySSN)
{
SocialSecurity="";
return FormatSSN(MySSN);
}

string getName(string MyName)
{
name="";
return MyName;
}

// Destructor
~Employee() {}

bool IsValidSSN(int SSN)
{
int num_digits=0;
if (SSN < 0)
{
return false;
}
while(SSN > 0)
{
num_digits++;

if (num_digits>9)
{
return false;
}
SSN/=10;
}

if (num_digits<9)
{
return false;
}

return true;

}

string FormatSSN(int SSNint)
{
if (IsValidSSN(SSNint))
{
char cNumber[10];
SSNint = sprintf_s(cNumber,"%d",SSNint);

for (int i=0; i<9; i++)
{
std::string s(1, cNumber); // Converts char to valid string
if (i==2)
{
SocialSecurity = SocialSecurity + s + "-";
}else if (i==4) {
SocialSecurity = SocialSecurity + s + "-";
}else{
SocialSecurity = SocialSecurity + s;
}
}
return SocialSecurity;
}else{
SocialSecurity="invalid";
return SocialSecurity;
}
}
};

class EmployeePay: public Employee
{
protected:
float Annual_Pay;
float Monthly_Pay;
int Dependents;
public:
// constructor
EmployeePay() {}
// Destructor
~EmployeePay() {}
};

class HourlyPay: public EmployeePay
{
private:
float Hourly_Pay_Rate;
float Overtime_Pay_Rate;
int Hours_Worked;
public:
// Default Constructor
HourlyPay() {}
// Destructor
~HourlyPay() {}
};


int main()
{
HourlyPay p;
int SSN=0;
cout << "Enter Social Security: " << endl;
cin >> SSN;

while (cin.fail())
{
cin.clear();
cin.ignore(100, '\n'); // skip 80 chars or to next end of line
whichever comes first
cout << "Invalid Social Security Number!!!!\n";
cout << "Try Again: " << endl;
cin >> SSN;
}

while(p.getSSN(SSN)=="invalid")
{
cin.clear();
cout << "Invalid Social Security Number!!!!";
cin >> SSN;
}
cout << p.getSSN(SSN);

system("PAUSE");
return 0;
}
 
O

osmium

rlueneberg said:
Yes it does Compile. The code is still under work but I am posting it
in full. I liked the last suggestion to keep SSN in string.
I believe
this will avoid a lot of headaches with int validation.

I have doubts whether you really understood the suggestion. What you posted
uses both int and string. The intent was to avoid the use of int at all.
int main()
{
HourlyPay p;
int SSN=0;
cout << "Enter Social Security: " << endl;
cin >> SSN;
<snip>

See what I mean?

I had to use google to get any indentation at all. And then it was totally
gross!. Could you indent something like three spaces instead of using tab?
 
R

rlueneberg

Yes, I did. I just posted the code as is to get an idea. I am working
on changing it to string type right now I will post the final one as
soon as I can...

Thank you

Rod
 
R

rlueneberg

Finally works after your suggestions. I just changed a couple of
things. The code looks cleaner too and I don't have to deal with
integer inputs. I thought that storing SSN as integer data member
would be easier to manipulate. But turns out to be a problem. I don't
like to save formated data in data members but that is part of the
assignment. Please send your comments.

#include <iostream>
#include <string>
#include "stdafx.h"
#include <ctype.h>

using namespace std;

class Employee
{
protected:
// Full Name
string name;
// Employee Number
char EmployeeNumber[5];
// Social Security Number
string SocialSecurity;
// Hire Date
string HireDate;
public:
// constructor
Employee()
{
SocialSecurity="";
}

string getSSN(string MySSN)
{
return FormatSSN(MySSN);
}

string getName(string MyName)
{
name="";
return MyName;
}

// Destructor
~Employee() {}

bool IsValidSSN(string SSN)
{
bool valid = true;

if (SSN.length()> 9)
{
valid=false;
}

char c[10];
strncpy (c,SSN.c_str(),10);

for (int i=0; i<9; i++)
{
if (!isdigit(c))
{
valid=false;
break;
}
}
return valid;
}

string FormatSSN(string SSN)
{
char c[10];
strncpy (c,SSN.c_str(),10);

for (int i=0; i<9; i++)
{
// Converts char to valid string
std::string s(1, c);
if (i==2)
{
SocialSecurity = SocialSecurity + s + "-";
}else if (i==4) {
SocialSecurity = SocialSecurity + s + "-";
}else{
SocialSecurity = SocialSecurity + s;
}
}
return SocialSecurity;
}



};

class EmployeePay: public Employee
{
protected:
float Annual_Pay;
float Monthly_Pay;
int Dependents;
public:
// constructor
EmployeePay() {}
// Destructor
~EmployeePay() {}
};

class HourlyPay: public EmployeePay
{
private:
float Hourly_Pay_Rate;
float Overtime_Pay_Rate;
int Hours_Worked;
public:
// Default Constructor
HourlyPay() {}
// Destructor
~HourlyPay() {}

};


int main()
{
HourlyPay p;
string SSN;
cout << "Enter Social Security: " << endl;
cin >> SSN;
if (p.IsValidSSN(SSN))
{
cout << "SSN is valid" << p.getSSN(SSN);
}else{
cout << "SSN is Invalid";
}

system("PAUSE");
return 0;
}
 
D

Default User

Yes, I did. I just posted the code as is to get an idea. I am working
on changing it to string type right now I will post the final one as
soon as I can...

What are you talking about? Please quote a relevant portion of the
previous message for context. Google Groups does that automatically
now, so you have no excuse.




Brian
 
J

James Kanze

Finally works after your suggestions. I just changed a couple of
things. The code looks cleaner too and I don't have to deal with
integer inputs. I thought that storing SSN as integer data member
would be easier to manipulate.

It is, in a way. If you store it as an int, it's a lot easier
to multiply two SSN's, for example. "Easier to manipulate"
isn't necessarily an advantage, until you define the
manipulations.
But turns out to be a problem. I don't
like to save formated data in data members but that is part of the
assignment. Please send your comments.
#include <iostream>
#include <string>
#include "stdafx.h"
#include <ctype.h>
using namespace std;
class Employee
{
protected:

Just a question: why protected? I rarely have protected data,
and then there is a very good reason. In this case, you don't
have a virtual destructor, so it is probable that the class
isn't meant to be inherited from anyway. As a general rule,
everything should be as restricted as possible.
// Full Name
string name;
// Employee Number
char EmployeeNumber[5];

Which is a wierd declaration. What is it, text or a number?
// Social Security Number
string SocialSecurity;
// Hire Date
string HireDate;
public:
// constructor
Employee()
{
SocialSecurity="";
}
string getSSN(string MySSN)
{
return FormatSSN(MySSN);
}
string getName(string MyName)
{
name="";
return MyName;
}
// Destructor
~Employee() {}
bool IsValidSSN(string SSN)
{
bool valid = true;
if (SSN.length()> 9)
{
valid=false;
}

That has to be wrong. At the very least, you should allow
leading and trailing spaces.
char c[10];
strncpy (c,SSN.c_str(),10);
for (int i=0; i<9; i++)
{
if (!isdigit(c))
{
valid=false;
break;
}
}
return valid;
}

string FormatSSN(string SSN)
{
char c[10];
strncpy (c,SSN.c_str(),10);
for (int i=0; i<9; i++)
{
// Converts char to valid string
std::string s(1, c);
if (i==2)
{
SocialSecurity = SocialSecurity + s + "-";
}else if (i==4) {
SocialSecurity = SocialSecurity + s + "-";
}else{
SocialSecurity = SocialSecurity + s;
}
}
return SocialSecurity;
}


What you've written is simply the equivalent of:

SocialSecurity = SSN.substr( 0, 3 )
+ '-' + SSN.substr( 3, 2 )
+ '-' + SSN.substr( 5 ) ;

Why not write it that way, and be done with it?

Also: what is the correct format: a string of digits, or a
string of digits with some separators? You don't want to output
one format, and require input in another. (The obvious way of
validating the input would be to use boost::regex. I'd reformat
it to the target format at the same time, catching the numeric
substrings in the regular expression, and pasting them together
more or less like the above.)
class EmployeePay: public Employee

EmployeePay is an Employee? Either the names are wrong, or using
inheritance is wrong.

And of course, if you're going to do this sort of derivation,
you need a virtual destructor in the base class.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,767
Messages
2,569,572
Members
45,045
Latest member
DRCM

Latest Threads

Top