Please

Hello everyone,

This is part of my code. I cannot get this to stop asking for money. Even when the customers pays over or in full, it never reads "Thanks for your purchase" or dispense change...


Can someone please help? I have pasted only that part of my very long code

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
//Function Money handler
double moneyHandler(double price, double coin)
{
	// valid is first coin input checked
	bool checking = false; //second coin input
	double total_coin = 0.0;
	double change = 0.0;
	double addtional = 0.0;
	bool cont = false;
	bool valid = false;

	do
	{
		cin >> coin;
		valid = isValidMoney(coin);
		cout << "taken " << valid << endl;
		//total_coin += coin;
		//change = static_cast <double> (price - total_coin);

		if ((valid == true) && (total_coin < price) && ((coin == NICKEL) || (coin == DIME) || (coin == QUARTER) || (coin == DOLLAR)))
		{
			addtional = coin;
			total_coin = total_coin + addtional;
			coin = 0.0;
			cout << addtional << " Dollars accepted" << endl;
			addtional = 0;
			cout << "You have added a total of " << total_coin << " Dollars" << endl;
			change = static_cast <double> (price - total_coin);
			cout << "You will still need to add " << change << " Dollars" << endl;
			cout << "Please add more valid coins to pay for your drink" << endl;
			cont = true;
			if ((checking == true) && (cont == true) && (total_coin < price) && ((coin == NICKEL) || (coin == DIME) || (coin == QUARTER) || (coin == DOLLAR)))
			{
				addtional = coin;
				coin = 0.0;
				total_coin = total_coin + addtional;
				cout << addtional << " Dollars accepted" << endl;
				cout << "you have added a total of " << total_coin << " Dollars" << endl;
				change = static_cast <double> (price - total_coin);
				cout << " You will still need to add " << change << " Dollars" << endl;
				cout << "Please add more valid coins to pay for your drink" << endl;
				cont = true;
			}
			else if ((checking == false) && (cont == true) && (total_coin < price) && ((coin == NICKEL) || (coin == DIME) || (coin == QUARTER) || (coin == DOLLAR)))
			{
				cout << "Not a valid coin, for it to be accepted please enter only the following denominations: $ 0.05 or $ 0.10 or $ 0.25 or $ 1.00 " << endl;
				coin = 0.0;
				addtional = 0.0;
				cout << addtional << " Dollars accepted" << endl;
				cout << "you have added a total of " << total_coin << " Dollars" << endl;
				change = static_cast <double> (price - total_coin);
				cout << " You will still need to add " << change << " Dollars" << endl;
				cout << "Please add more valid coins to pay for your drink" << endl;
				cont = true;
			}
			else if ((checking == true) && (cont == false) && (total_coin > price) && ((coin == NICKEL) || (coin == DIME) || (coin == QUARTER) || (coin == DOLLAR)))
			{
				addtional = coin;
				coin = 0.0;
				total_coin = total_coin + addtional;
				cout << addtional << " Dollars accepted" << endl;
				addtional = 0.0;
				cout << "You don't need to enter any more coins" << endl;
				cout << "you have added a total of " << total_coin << " Dollars" << endl;
				change = static_cast <double> (price - total_coin);
				cout << " Please take your money back " << change << " Dollars" << endl;
				cont = false;
				return change;
			}
			else if ((valid == false) && (total_coin < price))
			{
				cout << "Not a valid coin, for it to be accepted please enter only the following denominations: $ 0.05 or $ 0.10 or $ 0.25 or $ 1.00 " << endl;
				coin = 0.0;
				addtional = coin;
				cout << addtional << " Dollars accepted" << endl;
				total_coin = total_coin + addtional;
				cout << "you have added a total of " << total_coin << " Dollars" << endl;
				change = static_cast <double> (price - total_coin);
				cout << " You will still need to add " << change << " Dollars" << endl;
				cout << "Please add more valid coins to pay for your drink" << endl;
				cont = true;
			}
			else if((price == total_coin) && (cont == false))
			{
				cout << "Thanks for your purchase " << endl;
				change = 0.0;
				cont = false;
				return change;
			}
		}
	} while ((total_coin <= price) && (cont == true));
};
Last edited on
Without going too deeply, I already see the function signature could be a problem. How is this function moneyHandler being called? More specifically, what were you trying to do with double coin parameter? Currently it's passed in as a value copy, but then its value is overwritten with the cin on line 14.

Can you give a specific example of input, expected output, and what actually happens?
Hello Icy1,

Essentially this is a vending machine. The user selects a drink, and the machine ask for payment. What the issue is, is that it never stops asking for money.
Hard to follow the logic with so many checks. I highly recommend completely refactoring to use a switch statement. Since switch cannot be used with float or double, we do a little math to turn to int. Similarly, we can also now neatly create an enum for the coins. Again, enum is not allowed with float/double, so I'm guessing you had a bunch of const doubles running about in global space.

Try this, running at https://repl.it/repls/AbleLightgreyAdmin
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
#include <iostream>
#include <iomanip>
#include <cmath>
#include <limits>

using namespace std;

enum Coin
{
    PENNY = 1,
    NICKEL = 5,
    DIME = 10,
    QUARTER = 25,
    DOLLAR = 100
};

// Prompts for drink payment, one coin at a time, and returns change
double MoneyHandler(double price)
{
    cout << "Please enjoy your drink." << endl;
    cout << "Enter a valid coin value [0.05, 0.10, 0.25, 1] to pay for it." << endl << endl;
    int cents;
    double coin;
    double epsilon = 0.001;
    
    while ( price-epsilon > 0.0)  // Careful when price could be 0
    {
        cout << "Remaining balance: $" << price << endl;
        cout << "? ";
        cin >> coin;
        cents = (int)100*coin;
        
        switch(cents)
        {
            case PENNY:
                cout << "Sorry, pennies are not accepted here." << endl;
                break;
                
            case NICKEL:
            case DIME:
            case QUARTER:
            case DOLLAR:
                cout << "Thank you." << endl;
                price -= coin;
                break;
            
            // Make sure bad input doesn't cause infinite loop
            default:
                cout << "Your coin '" << coin << "' is not valid." << endl <<
                        "Should be one of [0.05, 0.10, 0.25, 1]" << endl;
                cin.clear();
                cin.ignore(numeric_limits<streamsize>::max(), '\n');
                break;
        }
    }
    
    cout << endl << "Drink is fully paid for!" << endl;
    return fabs(price);
}

int main()
{
    cout << fixed << setprecision(2);
    double change = MoneyHandler(0.55);
    cout << "Returned change: $" << change << endl;
    
    return 0;
}


There are a few gotchas, e.g. making sure bad input like "$" is handled (could be infinite loop), and possible floating comparison with 0, which might have been your issue (you didn't give specific example).

Suppose you have a while (price - paid > 0.0) condition that simplifies to:
0.05 - 0.05 > 0.0
This can actually still be true and never end, due to the impreciseness of floating point comparisons. 0.05 - 0.05 could actually be stored as 0.000000000000000002351. One strategy is to expect a rounding error, and know that if you want it to be accurate to 0.01, then to make use of an epsilon variable set to 0.001. See my code example for how i dealt with it.
Last edited on
Hints:
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
#include <algorithm>
#include <exception>
#include <iomanip>
#include <iostream>
#include <limits>
#include <string>
#include <vector>

struct Beverage {
    std::string name;
    int price,
        quantity,
        sold;
    Beverage();
    Beverage(std::string name_arg, int price_arg,
             int quantity_arg,     int sold_arg = 0);
};

Beverage::Beverage() : name { "unknown" }, price {}, quantity {}, sold {} {}

Beverage::Beverage(std::string name_arg, int price_arg, int quantity_arg, int sold_arg)
    : name { name_arg },
      price { price_arg },
      quantity { quantity_arg },
      sold { sold_arg }
{}

const std::vector<int> COINS { 5, 10, 25, 100 };

//Function Prototypes
unsigned getBeverage(std::vector<Beverage>& drinks);
void clearCin();
int askPayment(const Beverage& b, int credit = 0);
int moneyHandler();
int askForInt(int min, int max);
double askForDouble(double min, double max);
void updateBeverageQty(Beverage& b);
void updateSoldBeverageQty(Beverage& b);
int giveBackMoney(int howmuch);
std::string displayInCent(int val);

int getChoice();
void computeTotalProfit(std::vector<double>& prof, const std::vector<Beverage>& bev);
void displayTotalProfit(const std::vector<double>& prof, const std::vector<Beverage>& bev);
unsigned getBestPerformer(const std::vector<double>& prof);
unsigned getWorstPerformer(const std::vector<double>& prof);
void displayTabHeader();
void displayDrink(const Beverage& bev, double d);
void waitForEnter();

int main()
{
    // Load machine
    std::vector<Beverage> beverages { { "Coca-Cola",    150, 20 },
                                      { "Sprite",       125, 20 },
                                      { "Gatorade",     225, 20 },
                                      { "Spring-Water", 185, 20 } };

    int credit {};      // if user is owed money
    char userAnswer = 'Y';
    do {
        unsigned drink = getBeverage(beverages);
        if(drink == 'X') {
            credit = giveBackMoney(credit);
            continue;
        }
        credit += askPayment(beverages.at(drink), credit);
        updateBeverageQty(beverages.at(drink));
        updateSoldBeverageQty(beverages.at(drink));

        std::cout << "Do you want another beverage? (Y/n):";
        std::cin >> userAnswer;

    } while (userAnswer == 'Y' || userAnswer == 'y');
    credit = giveBackMoney(credit);

    int operation {};
    std::vector<double> profit;
    computeTotalProfit(profit, beverages);

    do {
        operation = getChoice();
        switch (operation)
        {
        case 1:                             // display total profit
            displayTotalProfit(profit, beverages);
            break;
        case 2: {                           // Best
            unsigned index = getBestPerformer(profit);
            displayTabHeader;
            displayDrink(beverages.at(index), profit.at(index));
        }
            break;
        case 3: {                           // worst
            unsigned index = getWorstPerformer(profit);
            displayTabHeader;
            displayDrink(beverages.at(index), profit.at(index));
        }
            break;
        case 4:
            return 0;       // exit from program
        }
    } while (0 < operation && operation < 5);

    waitForEnter();
    return 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
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
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215

// Ask the user for the requested beverage.
// Return an unsigned between 0 and drinks.size() - 1 or 'X' (<-- 88)
unsigned getBeverage(std::vector<Beverage>& drinks)
{
    unsigned choice = 0;
    while (choice < 1 || drinks.size() < choice) {
        std::cout << "\nWelcome to COP 1334 Vending Machine\n"
                     "Please choose one of the following refreshing options\n\n"
                  << std::setw(23) << "-__DRINK NAME_________-"
                  << std::setw(8)  << "-___PRICE"
                  << std::setw(12) << "-QUANTITY-\n";

        unsigned i{};
        for (const auto& b : drinks) {
            std::cout << ++i << ". " << std::setw(23) << std::left << b.name
                      << " $"  << displayInCent(b.price)
                      << std::setw(9) << std::right << b.quantity
                      << '\n';
        }
        std::cout << ++i << " to get your change.\n";
        choice = askForInt(1, i);
        if(choice == i) return 'X';
    }
    return choice - 1;
}

void clearCin()
{
    std::cin.clear();
    std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
}

// Ask the user money.
// Returns difference payment - price.
int askPayment(const Beverage& b, int credit)
{
    std::cout << "\nSelected: " << b.name << '\n';
    while(credit < b.price) {
        std::cout << " - payed: "  << displayInCent(credit)
                  << " - to pay: " << displayInCent(b.price - credit) << '\n';
        credit += moneyHandler();
    }
    return credit - b.price;
}

// Ask for a double, returns an accepted integer
int moneyHandler()
{
    int retval {};
    do {
        double d = askForDouble(*COINS.cbegin() / 100, *COINS.crbegin() / 100);
        retval = static_cast<int>(d * 100); // control needed
        for(const int i : COINS) {
            if(retval == i) { return retval; }
        }
        retval = 0;
        std::cout << "Accepted coins: ";
        for(const int i : COINS) { std::cout << displayInCent(i) << ' '; }
        std::cout << '\n';
    } while(retval == 0);
}

// Returns an int between min and max
int askForInt(int min, int max)
{
    std::cout << ">>> ";
    for(std::string s; std::getline(std::cin, s); /**/) {
        try {
            int i = std::stoi(s);
            if(i < min)      { std::cout << "Too little!"; }
            else if(i > max) { std::cout << "Too big!"; }
            else             { return i; }
            std::cout << " Please try again.\n>>> ";
        } catch(std::invalid_argument& e) {
            std::cout << "Wrong input. Please try again.\n>>> ";
        } catch(std::out_of_range& e) {
            std::cout << "Too big! Please try again.\n>>> ";
        }
    }
}

// Returns a double between min and max
double askForDouble(double min, double max)
{
    std::cout << ">>> ";
    for(std::string s; std::getline(std::cin, s); /**/) {
        try {
            double d = std::stod(s);
            if(d < min)      { std::cout << "Too little!"; }
            else if(d > max) { std::cout << "Too big!"; }
            else             { return d; }
            std::cout << " Please try again.\n>>> ";
        } catch(std::invalid_argument& e) {
            std::cout << "Wrong input. Please try again.\n>>> ";
        } catch(std::out_of_range& e) {
            std::cout << "Too big! Please try again.\n>>> ";
        }
    }
}

// Function to update beverage quantity (in stock)
void updateBeverageQty(Beverage& b) { --b.quantity; }

// Function to update beverage quantity (sold)
void updateSoldBeverageQty(Beverage& b) { ++b.sold; }

int giveBackMoney(int howmuch)
{
    if(!howmuch) {
        std::cout << "\nI owe you nothing!\n";
        return 0;
    }
    std::cout << "\nI'm giving you back:\n";
    for(auto it = COINS.crbegin(); it != COINS.crend(); ++it) {
        int mycount{};
        for(; (howmuch - *it) >= 0; ++mycount) { howmuch -= *it; }
        std::cout << mycount << " x " << displayInCent(*it) << '\n';
    }
    return howmuch;
}

std::string displayInCent(int val)
{
    std::stringstream ss;
    ss << val / 100 << '.';
    if(val % 100 < 10) { ss << 0; }
    ss << val % 100;
    return ss.str();
}

//Function choose operations
int getChoice()
{
    std::cout << "\nPlease select one of the following choices:\n"
                 "1. Display Total Profit\n"
                 "2. Display Best Performer\n"
                 "3. Display Worse Performer\n"
                 "4. Exit\n";
    return askForInt(1, 4);
}

//Function that calculates total profit
void computeTotalProfit(std::vector<double>& prof, const std::vector<Beverage>& bev)
{
    for (const auto& a : bev) { prof.push_back((a.sold * a.price) / 100); }
}

//Function that displays total profit
void displayTotalProfit(const std::vector<double>& prof, const std::vector<Beverage>& bev)
{
    displayTabHeader();
    //data display
    for (unsigned k = 0; k < prof.size(); ++k) {
        displayDrink(bev.at(k), prof.at(k));
    }
}

void displayTabHeader()
{
    std::cout << std::setw(14) << "DRINK NAME"
              << std::setw(10) << "PRICE"
              << std::setw(10) << "# SOLD"
              << std::setw(12) << "TOTAL PROFIT"
              << '\n';
    //display line in between
    std::cout << std::setfill(' ') << std::setw(4) << " "
              << std::setfill('-') << std::setw(40) << "-"
              << std::setfill(' ') << '\n';
}

// Function to calculate the best performing drink in $$
unsigned getBestPerformer(const std::vector<double>& prof)
{
    double largest{};
    unsigned index{};
    for(unsigned u{}; u < prof.size(); ++u) {
        if(prof.at(u) > largest) {
            largest = prof.at(u);
            index = u;
        }
    }
    return index;
}

//Function that displays best performer
void displayDrink(const Beverage& bev, double d)
{
    //data display
    std::cout << std::setw(14) << bev.name
    << std::setw(7) << "$" << displayInCent(bev.price)
    << std::setw(5) << bev.sold
    << std::setw(5) << "$" << d
    << '\n';
}

// Function to calculate the best performer $$
unsigned getWorstPerformer(const std::vector<double>& prof)
{
    double smallest = std::numeric_limits<double>::max();
    unsigned index;
    for (unsigned i = 0; i < prof.size(); ++i) {
        if (prof.at(i) < smallest) {
            smallest = prof.at(i);
            index = i;
        }
    }
    return index;
}

void waitForEnter()
{
    std::cout << "\nPress ENTER to exit...\n";
    std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
}

This should fix the problem... at line 91 I think.

1
2
if (total_coin >= price) { cont = false; } //insert this here
} while ((total_coin <= price) && (cont == true));

thank you all for your input. I was able to finally get this done =)
Topic archived. No new replies allowed.