Need help with implementing input validation to data structure

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
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.
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
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.