2011-10-16 23 views
15

Tôi đang cố lấy một vài tham số do người dùng nhập từ bảng điều khiển, hai chuỗi, hai int và double. Mã liên quan Tôi đang cố gắng để sử dụng là:C++ getline() không chờ kết nối từ bàn điều khiển khi được gọi nhiều lần

#include <string> 
#include <iostream> 
using namespace std; 

// ... 

string inputString; 
unsigned int inputUInt; 
double inputDouble; 

// ... 

cout << "Title: "; 
getline(cin, inputString); 
tempDVD.setTitle(inputString); 

cout << "Category: "; 
getline(cin, inputString); 
tempDVD.setCategory(inputString); 

cout << "Duration (minutes): "; 
cin >> inputUInt; 
tempDVD.setDuration(inputUInt); 

cout << "Year: "; 
cin >> inputUInt; 
tempDVD.setYear(inputUInt); 

cout << "Price: $"; 
cin >> inputDouble; 
tempDVD.setPrice(inputDouble); 

Tuy nhiên, khi chạy chương trình, thay vì chờ đợi cho inputString đầu tiên được nhập vào, các mã số không dừng lại cho đến khi getline thứ hai() gọi . Do đó, giao diện điều khiển đầu ra trông như thế này:

Tiêu đề: Thể loại:

với con trỏ xuất hiện sau khi loại. Nếu tôi nhập vào bây giờ, chương trình sau đó nhảy tiến tới đầu vào năm, không cho phép tôi nhập nhiều hơn một chuỗi. Điều gì đang xảy ra ở đây?

+0

Không thể sinh sản; xin vui lòng gửi thực, mã hoàn chỉnh. Tôi đặt cược vấn đề của bạn nằm ở nơi khác. Ngoài ra, không trộn đầu vào được định dạng và 'getline()'. –

+0

@KerrekSB: Tôi đồng ý rằng việc trộn chúng là một triệu chứng của kiểu xấu, nhưng lý do khách quan để không trộn chúng là gì? Tôi nghĩ rằng nó là hoàn toàn hợp lệ để trộn chúng, thực sự. – sehe

+0

@sehe: Vấn đề là việc trích xuất được định dạng không tiêu thụ các dòng mới, vì vậy rất dễ dàng để có được các kết quả không mong muốn khi bạn 'getline()' sau khi nghĩ rằng bạn đã xử lý tất cả dòng trước đó. Tôi không nói điều đó là không thể, nhưng nó thường làm cho logic rất khó đọc và duy trì. –

Trả lời

16

Vấn đề là bạn đang trộn các cuộc gọi đến getline() với việc sử dụng các nhà điều hành >>.

Hãy nhớ rằng toán tử >> bỏ qua khoảng trắng hàng đầu để chính xác sẽ tiếp tục trên các đường biên. Nhưng dừng đọc sau khi đầu vào đã được truy xuất thành công và do đó sẽ không nuốt ký tự '\ n'. Vì vậy, nếu bạn sử dụng một getline() sau khi >> bạn thường nhận được điều sai, trừ khi bạn cẩn thận (đầu tiên loại bỏ ký tự '\ n' không được đọc).

Bí quyết là không sử dụng cả hai loại đầu vào. Chọn cái thích hợp và dính vào nó.

Nếu đó là tất cả các số (hoặc đối tượng đẹp với toán tử >>) thì chỉ sử dụng toán tử >> (Chuỗi lưu ý là loại cơ bản duy nhất không đối xứng với đầu vào/đầu ra (tức là không chơi độc đáo)) .

Nếu đầu vào chứa chuỗi hoặc kết hợp nội dung sẽ yêu cầu getline() thì chỉ sử dụng getline() và phân tích cú pháp số ra khỏi chuỗi.

std::getline(std::cin, line); 
std::stringstream linestream(line); 

int value; 
linestream >> value; 

// Or if you have boost: 
std::getline(std::cin, line); 
int value = boost::lexical_cast<int>(line); 
7

Bạn cần xóa bộ đệm đầu vào. Nó có thể được thực hiện với cin.clear(); cin.sync();.

3

Sử dụng cin.clear() như đã đề cập sử dụng xử lý lỗi thích hợp:

cin.clear(); 
    cin.sync(); 

    cout << "Title: "; 
    if (!getline(cin, inputString)) exit 255; 
    tempDVD.setTitle(inputString); 

    cout << "Category: "; 
    if (!getline(cin, inputString)) exit 255; 
    tempDVD.setCategory(inputString); 

    cout << "Duration (minutes): "; 
    if (!(cin >> inputUInt)) exit 255; 
    tempDVD.setDuration(inputUInt); 

    cout << "Year: "; 
    if (!(cin >> inputUInt)) exit 255; 
    tempDVD.setYear(inputUInt); 

    cout << "Price: $"; 
    if (!(cin >> inputDouble)) exit 255; 
    tempDVD.setPrice(inputDouble); 
+1

Cảm ơn. Mã chỉ hoạt động nếu cả cin.clear() và cin.sync() được sử dụng. – user754852

+0

Cách dễ nhất để kết hợp toán tử >> với phương thức getline() là nhập cin.ignore() trước khi bất kỳ lệnh gọi nào để đường đệm được xóa bỏ bất kỳ ký tự dòng mới nào từ đầu vào trước đó. –

0

Trộn đường nối() với luồng đầu vào nói chung là điều xấu. Về mặt lý thuyết có thể xử lý thủ công các bộ đệm bẩn còn sót lại bằng cách sử dụng các luồng, nhưng đó là một nỗi đau không cần thiết mà chắc chắn nên tránh.

Bạn nên sử dụng thư viện bảng điều khiển để lấy thông tin nhập của mình, cách này có thể được làm mờ cho bạn.

Hãy xem TinyCon. Bạn chỉ có thể sử dụng phương thức tĩnh tinyConsole :: getLine() thay thế cho các cuộc gọi dòng và getline của bạn, và bạn có thể sử dụng nó bao nhiêu lần tùy thích.

Bạn có thể tìm thông tin ở đây: https://sourceforge.net/projects/tinycon/

4

Bạn có thể sử dụng

cin.ignore(); 

hoặc sử dụng như đã đề cập @kernald

cin.clear(); 
cin.sync(); 

trước khi sử dụng getline()

Các vấn đề liên quan