Vấn đề phổ biến: sau scanf(), ký tự newline \n còn lại trong buffer khiến fgets() hoặc getchar() tiếp theo đọc ngay dòng trống.
C - Các phương pháp
1. fflush(stdin) - KHÔNG CHUẨN (Chỉ MSVC hỗ trợ)
// CHỈ HOẠT ĐỘNG TRÊN MSVC (Windows) fflush(stdin); // Undefined behavior theo chuẩn C!
2. Vòng lặp đọc hết ký tự (Portable, khuyến nghị)
void clearInputBuffer() {
int c;
while ((c = getchar()) != '\n' && c != EOF) {
// Bỏ qua ký tự
}
}
3. scanf với format specifier (Đọc và bỏ qua whitespace)
// Dấu space trước %c bỏ qua mọi whitespace (kể cả \n)
scanf(" %c", &ch); // Space quan trọng!
// %*c đọc và hủy 1 ký tự
scanf("%d%*c", &num); // Đọc int, bỏ 1 ký tự (thường là \n)
4. fgets + sscanf (An toàn nhất)
char line[256];
if (fgets(line, sizeof(line), stdin)) {
sscanf(line, "%d", &num);
// Buffer đã sạch vì fgets đọc hết dòng
}
C++ - std::cin
1. cin.ignore() - Chuẩn C++
#include <iostream>
#include <limits>
int main() {
int n;
std::cin >> n;
// Bỏ qua đến newline hoặc max stream size
std::cin.ignore(std::numeric_limits::max(), '\n');
// Bây giờ getline an toàn
std::string line;
std::getline(std::cin, line);
}
2. ws manipulator (Bỏ qua whitespace)
std::string line; std::getline(std::cin >> std::ws, line); // Bỏ whitespace đầu, đọc dòng
Ví dụ hoàn chỉnh C++
#include <iostream>
#include <string>
#include <limits>
int main() {
int age;
std::string name;
std::cout << "Tuổi: ";
std::cin >> age;
// XÓA BUFFER - QUAN TRỌNG
std::cin.ignore(std::numeric_limits::max(), '\n');
std::cout << "Tên: ";
std::getline(std::cin, name);
std::cout << "Tuổi: " << age << ", Tên: " << name << '\n';
return 0;
}
So sánh phương pháp
| Phương pháp | Ngôn ngữ | Portable | An toàn | Khuyến nghị |
|---|---|---|---|---|
| fflush(stdin) | C | Không (chỉ MSVC) | UB | KHÔNG DÙNG |
| while(getchar()!='\n') | C | Có | Có | OK |
| scanf(" %c") | C | Có | Có (cho char) | OK cho char |
| fgets + sscanf | C | Có | Rất an toàn | KHUYẾN NGHỊ |
| cin.ignore() | C++ | Có | Có | KHUYẾN NGHỊ |
| cin >> ws | C++ | Có | Có | OK cho string |