3

I have a little problem. I've created a program that asks user to enter part's name and part's price for four diffrent parts. Each name and price fills a structure, and I have an array of four structures. When i do a for loop to fill all the names and prices, my getline functon doesn't work properly, it simply just skipps the entering part after I enter the first part's name. Can you please tell me why? Here's my code:

#include <iostream>
#include <string>

struct part {
    std::string name;
    double cost;
};

int main() {

    const int size = 4;

    part apart[size];

    for (int i = 0; i < size; i++) {
        std::cout << "Enter the name of part № " << i + 1 << ": ";
        getline(std::cin,apart[i].name);
        std::cout << "Enter the price of '" << apart[i].name << "': ";
        std::cin >> apart[i].cost;
    }
}
lil broomstick
  • 518
  • 4
  • 18

1 Answers1

5

std::getline consumes the newline character \n, whereas std::cin will consume the number you enter and stop.

To illustrate why this is a problem, consider the following input for the first two 'parts':

item 1\n
53.25\n
item 2\n
64.23\n

First, you call std::getline, which consumes the text: item 1\n. Then you call std::cin >> ..., which recognises the 53.25, parses it, consumes it, and stops. You then have:

\n
item 2\n
64.23\n

You then call std::getline for a second time. All it sees is a \n, which is recognised as the end of a line. Therefore, it sees a blank string, stores nothing in your std::string, consumes the \n, and stops.

To solve this, you need to make sure the newline is consumed when you store the floating-point value using std::cin >>.

Try this:

#include <iostream>
#include <string>
// required for std::numeric_limits
#include <limits>

struct part {
    std::string name;
    double cost;
};

int main() {

    const int size = 4;

    part apart[size];

    for (int i = 0; i < size; i++) {
        std::cout << "Enter the name of part № " << i + 1 << ": ";
        getline(std::cin,apart[i].name);
        std::cout << "Enter the price of '" << apart[i].name << "': ";
        std::cin >> apart[i].cost;

        // flushes all newline characters
        std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
    }
}
Archimaredes
  • 1,315
  • 12
  • 23
  • I've already solved this problem by myself with a similar `cin.ignore`. But anyway, thanks! – lil broomstick Jan 30 '16 at 17:40
  • 1
    The newline character in C++ is `'\n'` on **all** systems. The difference between Windows and Unix is in how that character gets written to a file and in what is treated as a the end of a line on input. But that's all irrelevant here: when you press `enter` on the terminal, the input functions see `'\n'`. There's no `'\r'` involved. – Pete Becker Jan 30 '16 at 17:43
  • @PeteBecker Thanks - updated – Archimaredes Jan 30 '16 at 17:45
  • (It's an honour, by the way!) – Archimaredes Jan 30 '16 at 17:48
  • Your answer lays out the problem quite clearly. You might consider going on to what happens on the next extraction: in your example, after `getline` reads an empty line, `std::cin >> apart[i].cost;` will see the `'i'` in `"item 2"`, and the extraction will fail because that is not a valid representation of a floating-point value. That will set `std::cin` to a failed state, and any subsequent input attempts through `std::cin` will also fail. I've upvoted your answer; I don't think this addition is critical, and it might be too much of a distraction. – Pete Becker Jan 30 '16 at 17:58