0

I just started "Introduction to C++" this semester, and I'm stuck on an exercise that involves taking data from a table and writing a program that will let you input and display each item (line by line) showing the Item, Cost, and calculated Total Cost.

The program I've written works perfectly for the first item, but I need it to repeat the same 3 questions (allowing user input of different items/costs/discounts each time it repeats the questions), while printing the calculated total after each question is answered. I'm assuming this will involve either a do-while loop or a for loop, but I can't figure out how to integrate what I've already written into a loop.

#include <iostream>
using namespace std;

int main()
{
    string Item;
    float Cost;
    float Discount;
    float TotalCost;

    cout << "What is the item? \n";
    cin >> Item;

    cout << "What is the cost? \n";
    cin >> Cost;

    cout << "What is the discount? \n";
    cin >> Discount;

    TotalCost = Cost - Discount;
    
    cout << Item << "'s Total Cost is " << TotalCost;
    
    return 0;
}

I've tried making a for loop (code I've tried below), but it doesn't work, and I haven't been able to find any loop examples in my book or online that involve accepting user input each time the process loops.

#include <iostream>
using namespace std;

int main()
{
    string Item;
    float Cost;
    float Discount;
    float TotalCost;

    for (int a = 0; a < 5; a++)
    {
        cout << "What is the item? \n";
        cin >> Item;

        cout << "What is the cost? \n";
        cin >> Cost;

        cout << "What is the discount? \n";
        cin >> Discount;

        TotalCost = Cost - Discount;

        cout << Item << "'s Total Cost is " << TotalCost;
    }

    return 0;
}
Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
Elliot
  • 21
  • 1
  • 2
    Looks fine to me (except, you are missing `#include `, the loop will run 5 times not 4, and you are not outputting a separator after each iteration). What is the actual problem you are experiencing? Define "doesn't work" exactly. What is the actual input you are using? – Remy Lebeau Sep 28 '21 at 03:50
  • The items are Television, Ceiling Fan, Tires, and Clothes. The costs are 850.00, 156.00, 400.00, and 260.00. The discounts are 46.00, 12.00, 60.00, and 15.00. When I run the program it prints out the questions one by one so I can enter "Television", then "850", then "46" and it prints "Television's Total Cost is 804". I'm trying to get it to repeat the entire process so it will do that for all 4 of the items. – Elliot Sep 28 '21 at 03:58
  • Thanks! I've added #include and I've changed the condition statement to "a < 4" but the program still stops after printing "Television's Total Cost is 804" instead of looping back to ask "What is the item?" again. – Elliot Sep 28 '21 at 04:18
  • The loop is fine. But `cin >> Item` won't work the way you want for `Ceiling Fan` because of the space in the middle. `operator>>` stops reading on whitespace. So `cin >> Item` will read only `Ceiling` and then `cin >> Cost` will fail reading `Fan` instead of `156.00`. To read a string that contains spaces, use `std::getline()`, just watch out for [this issue](https://stackoverflow.com/questions/21567291/). – Remy Lebeau Sep 28 '21 at 04:25
  • @Remy Thank you!! After using std::ignore(); std::getline(std::cin, Item); in place of cin >> Item it works perfectly now! – Elliot Sep 28 '21 at 05:29
  • "I've tried making a for loop (code I've tried below), but it doesn't work" What does that mean? What happens when you try it, and how is that different from what is supposed to happen? Please read [ask]. – Karl Knechtel Sep 28 '21 at 05:47
  • @Elliot your use of `cin.ignore()` is wrong, read [the link](https://stackoverflow.com/questions/21567291/) I gave you again more carefully. You need to call it AFTER `operator>>`, not before `std::getline()`. Try this instead: `for (...) { ... getline(cin, Item); ... cin >> Cost; ... cin >> Discount; cin.ignore(numeric_limits::max(), '\n'); ... }` – Remy Lebeau Sep 29 '21 at 20:02

2 Answers2

0

Two things:

  1. We only run it 4 times, so it should be a < 4
  2. When you get the item, use the std::getline function. This will return everything the user enters, including spaces.
  3. We need to ignore empty lines. When we start the loop again, there's an empty line because the user pressed "enter" after entering the discount. So we need to put the getline in a loop, and read lines until finding one that's not empty.
  4. When you print the total cost at the end, put a newline so when the loop body starts again, we're on a new line.

Updated code:

#include <iostream>
using namespace std;

int main()
{
    string Item;
    float Cost;
    float Discount;
    float TotalCost;

    for (int a = 0; a < 4; a++) // (1)
    {
        cout << "What is the item? \n";
        do {
            // (2) Use the std::getline function to get the entire line.
            std::getline(std::cin, Item);

            // (3) Empty lines should be ignored. If the line is empty,
            // Get a line again.
        } while(Item.size() == 0);

        cout << "What is the cost? \n";
        cin >> Cost;

        cout << "What is the discount? \n";
        cin >> Discount;

        TotalCost = Cost - Discount;

        // (4) Put a newline here at the end to make sure the buffer
        // Gets flushed before the loop starts again.
        cout << Item << "'s Total Cost is " << TotalCost << '\n';
    }

    return 0;
}

You don't need to use an array for Cost, Discount, or TotalCost, because it's fine to overwrite those with each new loop iteration.

Alecto Irene Perez
  • 10,321
  • 23
  • 46
-1

Nice first try.

You need to use arrays, primitives like int, float and double only represent ONE number.

 #include <iostream>
 #include <array>
 #include <string>
 #include <locale>

 int main()
 {
     std::locale::global(std::locale(""));
     std::cout.imbue(std::locale());//Locale for complete-ness

     std::array<std::string,4> Item;
     std::array<float,4> Cost;
     std::array<float,4> Discount;
     std::array<float,4> TotalCost;

     for (size_t i = 0; i < 5; ++i)
     {
         std::cout << "What is the item? \n";             
         std::getline(std::cin, Item[i]);
         std::cout << "What is the cost? \n";
         std::cin >> Cost[i];

         std::cout << "What is the discount? \n";
         std::cin >> Discount[i];
        
         std::cin.ignore();//Fix carriage return issue.

         TotalCost[i] = Cost[i] - Discount[i];

         std::cout << Item[i] << "'s Total Cost is " << TotalCost[i];
     }//End for

     return EXIT_SUCCESS;
 }

This is fine in your case as you're just starting to learn, but please note: This is rarely the way we do it in real life.

You'd use a while loop and ask the user if they want to enter more items after each entry, this allows your program to be flexible in how much data it processes. (Note this requires the use of an std::vector<T> as that structure is automatically resizable)

We'd also use objects, but you're likely not going to be working with those for a bit yet. Best to get the basics down.

Some other tips:

  • avoid using namespace std;, this can cause problems when you start to work with libraries
  • std::string is an object, not a primitive, so you need #include <string>
  • In C++, array indexes start at zero, so your loop should be i < 5 NOT i < 4
  • Favor ++i instead of i++, some (albeit very old) compilers may generate more efficient code
  • In for loops, use size_t instead of int. size_t is always unsigned (no negative numbers) and will be a 32-bit int on 32-bit systems and (usually) a 64-bit int on 64-bit systems. This is more efficient, and prevents certain indexing errors
  • When exiting successfully, return EXIT_SUCCESS, otherwise EXIT_FAILURE (albeit this one is kind of a personal preference, and they are both macros, which are usually considered evil in C++)
dave_thenerd
  • 448
  • 3
  • 10
  • 1
    This program doesn't actually work, and using arrays here doesn't solve the problem. When you get the line, it's getting an empty line on the second iteration of the loop. – Alecto Irene Perez Sep 28 '21 at 05:21
  • This code suffers from [this issue](https://stackoverflow.com/questions/21567291/) – Remy Lebeau Sep 28 '21 at 05:46
  • @RemyLebeau Sorry, I'm always forgetting that issue. MSVC doesn't always have this problem if you compile with UTF-8 support and set a locale. – dave_thenerd Sep 29 '21 at 19:17
  • @dave_thenerd First, locales have nothing to do with the `getline` vs `operator>>` issue I pointed out. And second, your use of `cin.ignore()` is wrong. It needs to be after `std::cin >> Discount[i]`, not before `std::getline(std::cin, Item[i])`, and it should be more like `cin.ignore(numerric_limits::max(), '\n')` instead. – Remy Lebeau Sep 29 '21 at 19:20
  • This was the solution written on your own page pointed out to me. https://stackoverflow.com/questions/21567291/why-does-stdgetline-skip-input-after-a-formatted-extraction – dave_thenerd Sep 29 '21 at 19:23
  • @RemyLebeau Huh, I just tried it and it's creating a different issue than I thought the one described was. I actually don't think I've ever encountered this problem before. Maybe it's because I don't do a ton with the console these days. I mainly work in library development and when I do deal with I/O it's usually via the network a GUI or consists entirely of output. Anyway it's fixed now and I learned something new. – dave_thenerd Sep 29 '21 at 19:49
  • @dave_thenerd "*This was the solution written on your own page pointed out to me*" - then you misread what it says. You would need to call `ignore()` BETWEEN `>>` and `getline()`, to discard the `\n` that `>>` left behind. In your original example, you were calling `ignore()` before the 1st `getline()` without a preceding `>>`, so `getline()` would not see the 1st character of the user's input. – Remy Lebeau Sep 29 '21 at 19:57