Question

I wrote a program that uses getline() function, but I don't know how should I use getline() in the correct way. I've searched it on the Internet but I just found something about about using getchar() with getline() or cin.ignore(). I tried and none of them worked and I don't know what is the problem and why getline() function needs getchar() or cin.ignore() to work correctly?

My Input

2   
Alderaan   
1000.00 2000.00 3000.00   
Dantooine   
-1000.00 1000.00 1000.00   
Circarpous Major   
-500.00 500.00 -500.00   
Y’Toub   
-500.00 -500.00 500.00    

here is my code:

#include <cmath>
#include <string>
#include <cstdio>
#include <iostream>
using namespace std;
int main()
{
    long long int  x, y, z, x1, y1, z1;
    int n;
    cin >> n;
    string s, p;
    while (n--)
    {
        getline(cin, s);
        cin >> x;
        cin >> y;
        cin >> z; 
        cin.ignore();
        getline(cin, p);
        cin >> x1;
        cin >> y1;
        cin >> z1;
        cin.ignore();
        printf("%s to %s: %.2f\n", s.c_str(), p.c_str(), sqrt(pow(x - x1, 2) + pow(y - y1, 2) + pow(z - z1, 2)));
    }
}
Was it helpful?

Solution

The code mixes formatted input (i.e. using the >> operator for input) with unformatted input (in this case using std::getline()). Unformatted input does not skip leading whitespace while formatted input does skip leading whitespace. In both cases reading stops as soon as the input is the next character wouldn't fit the format.

For example, reading a double when the input is 3000.00\n... stops after reading the last 0 because the '\n doesn't fit the doubles format. The next character in the stream is, thus, a \n. The function std::getline() reads until it finds the first \n which is immediately: it extracts that one character and [successfully] produces an empty line. With your input the sequence Dantooine is next but doesn't fit the format of a double and the stream goes into fail state.

The simple fix is to always skip leading white space when switching from formatted input to unformatted input, e.g., using the std::ws manipulator:

std::getline(std::cin >> std::ws, s);

Whether this is suitable depends a bit on what you are trying to read. If the strings you want to read can start with a whitespace, you would need to be a bit more careful and, e.g., only extract whitespace up to the next newline:

std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');

(just ignoring one character may not work, e.g., if the input of the line ends in 3000.00 \n).

Reading 3000.00 as long actually stops at the ., i.e., the first change to your program is to correct the type of values read to be double rather than long. Note that you should also always check that your input was successful before processing it. That is, I would actually use something like this:

double      x0, y0, z0, x1, y1, z1;
std::string l0, l1;
while (0 < n--
       && std::getline(std::cin >> std::ws, l0)
       && std::cin >> x0 >> y0 >> z0
       && std::getline(std::cin >> std::ws, l1)
       && std::cin >> x1 >> y1 >> z1) {
    // do something with the input
}

OTHER TIPS

cin >> z does not consume the \n character. Thus you need a cin.ignore() to consume the newline character and make the next getline() reading the line you want. The same issue also happens on cin >> z1.

It's best not to mix token and line extraction. Just use string streams if you want to tokenize a line. I'd try this:

#include <string>
#include <sstream>
#include <iostream>

std::string n_str;   // for the first number, parse it later

if (!std::getline(std::cin, n_str))
{
    // error, die
}

for (std::string name, numbers;
     std::getline(std::cin, name) && std::getline(std::cin, numbers); )
{
    std::istringstream iss(numbers);
    double x, y, z;
    if (!(iss >> x >> y >> z >> std::ws) || iss.get() != EOF)
    {
        // parse error, die
    }

    // "name", "x", "y", "z" are usable now
}

try it

#include <cmath>
#include <string>
#include <cstdio>
#include <iostream>
using namespace std;
int main()
{
    long long int  x, y, z, x1, y1, z1;
    int n;
    cin >> n;
    string s, p;
    while (n--)
    {
        cin.ignore();
        cin.clear();
        getline(cin, s);
        cin >> x;
        cin >> y;
        cin >> z;
        cin.ignore();
        cin.clear();
        getline(cin, p);
        cin >> x1;
        cin >> y1;
        cin >> z1;
        printf("%s to %s: %.2f\n", s.c_str(), p.c_str(), sqrt(pow(x - x1, 2) + pow(y - y1, 2) + pow(z - z1, 2)));
    }
}

you have twice in the first time you enter the string.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top