Reputation: 2404
So this is the client part of my assignment that I'm coding.
#include "coordinate.h"
#include "gpscoord.h"
#include <QString>
#include <QTextStream>
#include <QCoreApplication>
QTextStream cout(stdout);
QTextStream cin(stdin);
int main(int argc, char* argv[])
{
QCoreApplication app(argc, argv);
GPSCoord gps;
int degrees, minutes, seconds;
char cardinalDirection;
cout << "\nPlease enter values for the latitude.." << endl;
cout << "Degrees : " << flush;
cin >> degrees;
cout << "Minutes : " << flush;
cin >> minutes;
cout << "Seconds : " << flush;
cin >> seconds;
cout << "Cardinal Direction : " << flush;
cin >> cardinalDirection;
gps.setCoord(degrees, minutes, seconds, cardinalDirection);
cout << "\nPlease enter values for the longitude.." << endl;
cout << "Degrees : " << flush;
cin >> degrees;
cout << "Minutes : " << flush;
cin >> minutes;
cout << "Seconds : " << flush;
cin >> seconds;
cout << "Cardinal Direction : " << flush;
cin >> cardinalDirection;
gps.setCoord(degrees, minutes, seconds, cardinalDirection);
cout << "\nGeographic Coordinates\t: " << gps.toString(false) << endl << "Decimal Coordinates\t: " << gps.toString(true) << endl;
return 0;
}
The first half works fine. But as soon as I enter the input for the first cardinalDirection, the program sets the coordinate but then just prints the rest of the output one after the other and doesn't want for any input. Here is the output.
Please enter values for the latitude..
Degrees : 25
Minutes : 46
Seconds : 3
Cardinal Direction : S
Please enter values for the longitude..
Degrees : Minutes : Seconds : Cardinal Direction :
Geographic Coordinates : 0ø, 0', 0", S ; 25ø, 46', 3",
Decimal Coordinates : 0 ; 25.775
Is it something stupid that I'm missing? Can't imagine what would cause this.
Upvotes: 2
Views: 632
Reputation: 98425
Qt has a bug QTBUG-37394, and your code has a bug too :)
Your bug: When reading single characters into either char
or QChar
, you will read whitespace that terminated any preceding input. You must use ws(stream)
to get rid of existing whitespace in the stream.
Qt bug: the character-reading operators wait for non-whitespace data even if there is already a whitespace character available in the input stream.
The reason it doesn't work is that what you consume as a character is the newline from the previous line.
After you enter, say, 20 arcseconds, the contents of the character buffer are:
{ '2', '0', '\n' }
After cin >> arcseconds
runs, the character buffer is:
{ '\n' }
Then, cin >> cardinalDirection
runs, and waits for new input since there's nothing interesting in the buffer (that's the Qt bug: it shouldn't wait). Suppose you enter N
, the character buffer is now:
{ '\n', 'N', '\n' }
Now, operator>>(char&)
correctly retrieves the first character in the buffer, no matter what it is. Thus it retrieves '\n'
and succeeds (that's your bug: you should get rid of the whitespace first). The character buffer now contains:
{ 'N', '\n' }
The problem is then that now you read the longitude. The buffer contains non-whitespace data, and the following executes immediately: cin >> degrees
.
As expected, reading an N
into an integer fails, and no further output is processed.
If you'd enter a digit, say 1
, it will succeed, and you will have the curious exchange when it asks for degrees, minutes, seconds, cardinal direction and then asks for minutes while skipping degrees.
The fix is to forcibly skip the whitespace in the the data. The documentation for QTextStream::ws()
method has this telling sentence:
This function is useful when reading a stream character by character.
#include <QTextStream>
#include <QCoreApplication>
QTextStream cout(stdout);
QTextStream cin(stdin);
class GPSCoord {
QString dir;
public:
void setCoord(int, int, int, char d) { dir.append(d); }
QString toString(bool) const { return dir; }
};
int main(int argc, char* argv[])
{
QCoreApplication app(argc, argv);
GPSCoord gps;
int degrees, minutes, seconds;
char cardinalDirection;
cout << "\nPlease enter values for the latitude.." << endl;
cout << "Degrees : " << flush;
cin >> degrees;
cout << "Minutes : " << flush;
cin >> minutes;
cout << "Seconds : " << flush;
cin >> seconds;
cout << "Cardinal Direction : " << flush;
ws(cin) >> cardinalDirection;
gps.setCoord(degrees, minutes, seconds, cardinalDirection);
cout << "\nPlease enter values for the longitude.." << endl;
cout << "Degrees : " << flush;
cin >> degrees;
cout << "Minutes : " << flush;
cin >> minutes;
cout << "Seconds : " << flush;
cin >> seconds;
cout << "Cardinal Direction : " << flush;
ws(cin) >> cardinalDirection;
gps.setCoord(degrees, minutes, seconds, cardinalDirection);
cout << "\nGeographic Coordinates\t: " << gps.toString(false) << endl
<< "Decimal Coordinates\t: " << gps.toString(true) << endl;
return 0;
}
Upvotes: 2
Reputation: 2257
cin
doesn't like your char cardinalDirection
. It works for me when I change the declaration to char cardinalDirection[2];
Edit: As Kuba Ober pointed out, this can lead to a buffer overflow situation. There's no real input validation or error handling in the existing code, but I should be more thorough in my own answers.
If you wish to restrict to a certain number of characters, you can do the following.
char cardinalDirection;
...
cout << "Seconds : " << flush;
cin >> seconds;
//read everything from the buffer to clear
//it out - there are still some newlines
//in the buffer from previous input
cin.readLine();
cout << "Cardinal Direction : " << flush;
//read one character from the input and convert it to a char
cardinalDirection = cin.readLine(1)[0].toAscii();
//in case the user entered more than 1 character, clear out the buffer again
//so that the next inputs will work correctly
cin.readLine();
...
Upvotes: -1