Need help with implementing input validation to data structure
Mar 17, 2020 at 11:24am UTC
I am in a bit of a pickle here trying to see how I can implement input validation with structure data types in a function. I am trying to make it so it accepts positive integers and no special characters.
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 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141
#include<iostream>
#include<iomanip>
#include<string>
using namespace std;
struct monthlyBudget
{
double housing = 580.00;
double utilities = 150.00;
double houseHoldExpenses = 65.00;
double transportation = 50.00;
double food = 250.00;
double medical = 30.00;
double insurance = 100.00;
double entertainment = 150.00;
double clothing = 75.00;
double miscellaneous = 50.00;
};
struct monthlySpent
{
double housing;
double utilities;
double houseHoldExpenses;
double transportation;
double food;
double medical;
double insurance;
double entertainment;
double clothing;
double miscellaneous;
};
void showData(monthlyBudget *);
void getExpenses(monthlySpent *, string);
void compareExpenses(monthlyBudget *, monthlySpent *, string);
int main()
{
monthlyBudget monthly;
monthlySpent spent;
monthlySpent *stdPtr2 = nullptr ;
monthlyBudget *stdPtr = nullptr ;
stdPtr = &monthly;
stdPtr2 = &spent;
string months;
showData(stdPtr);
getExpenses(stdPtr2, months);
compareExpenses(stdPtr, stdPtr2, months);
return 0;
}
void showData(monthlyBudget *m)
{
double total;
cout << "Here is your monthly budget for YEAR 2020:\n" << endl;
cout << "Housing " << setw(9) << "$" << m->housing << endl;
cout << "Utilities " << setw(7) << "$" << m->utilities << endl;
cout << "Household " << setw(7) << "$" << m->houseHoldExpenses << endl;
cout << "Transportation " << setw(2) << "$" << m->transportation << endl;
cout << "Food " << setw(12) << "$" << m->food << endl;
cout << "Medical " << setw(9) << "$" << m->medical << endl;
cout << "Insurance " << setw(7) << "$" << m->insurance << endl;
cout << "Entertainment " << setw(3) << "$" << m->entertainment << endl;
cout << "Clothing " << setw(8) << "$" << m->clothing << endl;
cout << "Miscellaneous " << setw(3) << "$" << m->miscellaneous << endl;
cout << "=================================================" << endl;
total = m->housing + m->utilities + m->houseHoldExpenses + m->transportation + m->food + m->medical + m->insurance + m->entertainment + m->clothing + m->miscellaneous;
cout << "Total budgeted " << setw(2) << "$" << total << endl;
cout << "=================================================" << endl;
cout << endl;
}
void getExpenses(monthlySpent *s, string months)
{
cout << "Enter month of expenditure: " ;
cin >> months;
cout << endl;
cout << "Enter actual monthly expenditures for each budget category" << endl;
cout << endl;
cout << "Housing: " << setw(9) << "$" ;
cin >> s->housing;
cout << "Utilities: " << setw(7) << "$" ;
cin >> s->utilities;
cout << "Household: " << setw(7) << "$" ;
cin >> s->houseHoldExpenses;
cout << "Transportation: " << setw(2) << "$" ;
cin >> s->transportation;
cout << "Food: " << setw(12) << "$" ;
cin >> s->food;
cout << "Medical: " << setw(9) << "$" ;
cin >> s->medical;
cout << "Insurance: " << setw(7) << "$" ;
cin >> s->insurance;
cout << "Entertainment: " << setw(3) << "$" ;
cin >> s->entertainment;
cout << "Clothing: " << setw(8) << "$" ;
cin >> s->clothing;
cout << "Miscellaneous: " << setw(3) << "$" ;
cin >> s->miscellaneous;
cout << endl;
}
void compareExpenses(monthlyBudget *m, monthlySpent *s, string months)
{
cout << " Budgeted" << " Spent" << " Difference" << endl;
cout << "======================================================" << endl;
cout << "Housing " << setw(13) << m->housing << setw(12) << s->housing << endl;
cout << "Utilities " << setw(11) << m->utilities << setw(12) << s->utilities << endl;
cout << "Household " << setw(10) << m->houseHoldExpenses << setw(13) << s->houseHoldExpenses << endl;
cout << "Transportation " << setw(5) << m->transportation << setw(13) << s->transportation << endl;
cout << "Food " << setw(16) << m->food << setw(12) << s->food << endl;
cout << "Medical " << setw(12) << m->medical << setw(13) << s->medical << endl;
cout << "Insurance" << setw(12) << m->insurance << setw(12) << s->insurance << endl;
cout << "Entertainment " << setw(7) << m->entertainment << setw(12) << s->entertainment << endl;
cout << "Clothing " << setw(11) << m->clothing << setw(13) << s->clothing << endl;
cout << "Miscellaneous " << setw(6) << m->miscellaneous << setw(13) << s->miscellaneous<< endl;
}
Last edited on Mar 17, 2020 at 11:24am UTC
Mar 17, 2020 at 10:18pm UTC
The first thing to do is recognize that:
the user will always press ENTER after every requested input
This makes getting input easy: use getline() and get a string.
Once you have that string, try to convert it to the type you desire and perform any other checks you want on it, such as range bounds.
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
#include <ciso646>
#include <iostream>
#include <optional>
#include <sstream>
#include <string>
template <typename T>
std::optional<T> string_to( const std::string & s )
{
std::istringstream ss( s );
T result;
try
{
ss >> result >> std::ws;
if (!ss.eof()) throw 1;
return result;
}
catch (...)
{
return {};
}
}
int ask_integer( int min, int max )
{
std::string s;
getline( std::cin, s );
auto x = string_to<int >( s );
if (!x or (*x < min) or (*x > max))
{
std::cerr << "That ain't yo age, foo!\n" ;
exit( 1 );
}
return *x;
}
int main()
{
std::cout << "What is your age? " ;
int age = ask_integer( 0, 120 );
std::cout << "Good job! You are " << age << " years old!\n" ;
}
Hope this helps.
Ack! Gotta run! if I typoed something let me know.
Mar 18, 2020 at 12:43am UTC
If I typoed something let me know.
The use of
throw for local control flow is always suspect.
Also, the
operator>> is potentially user-provided. It may be an error to
catch(...) and swallow arbitrary exceptions thrown from user code.
1 2 3 4 5 6 7 8 9
template <typename T>
std::optional<T> string_to( const std::string & s )
{
std::istringstream ss( s );
T result;
ss >> result >> std::ws;
if (!ss.eof()) return std::nullopt;
else return result;
}
Last edited on Mar 18, 2020 at 12:43am UTC
Mar 18, 2020 at 8:14pm UTC
Yeah... I was thinking those things as I wrote that version of my string_to<>() function...
What you posted is my canonical version.
Still not sure why I did that.
It was late... and... I have no excuse. /hangs head in shame
Topic archived. No new replies allowed.