Trải nghiệm dùng cin.fail() liên tục trả về giá trị lỗi. Hàm kiểm tra kiểu dữ liệu nhập và giới hạn giá trị

Trong hàm này mình muốn kiểm tra dữ liệu đầu vào có đúng là float không hay có lẫn ký tự nào vậy nên mình sử dụng hàm cin.fail().Nếu mình nhập vào biến input(cin >> input) mà có ký tự char nào thì nó sẽ báo không nhập được.
Mọi người thấy điều kiện kết thúc vòng lặp nhập input là cin.fail() phải trả về false.Tuy nhiên cin.fail() là một hàm return và nó có trả về một cờ lỗi.Giá trị này không được resert sau khi bạn dùng cin.fail().Do vậy cờ check của mình luôn trả về giá trị fail dẫn đến vòng lặp vô tận.Đồng thời vì cờ của cin.fail() đang trả về true nên nó cũng ngăn cản khả năng vận hành của lệnh cin >> input;
Vậy nên đây là cách khắc phục thêm vào một hàm cin.clear() để reset cờ đồng thời thêm cả cin.ignore() hoặc fflush(stdin) trong thư viện stdio.h để dọn bộ nhớ đệm vì nó vẫn đang chứa giá trị nhập sai từ bàn phim trước đó.

#include <iostream>
#include <stdio.h>
using namespace std;
float nhap_float(float input,float minx,float max)//kiem soat data type,min,max nhap vao
{
	bool check;//kiem tra do hop le cua input hop le = true
		do 
		{
			check = false;
			cin.clear();
			cin >> input;
			if (cin.fail()) 
			{//du lieu khong hop le
				cout << "Khong duoc phep nhap so khong ky tu dac biet\n";
				check = false;
			}
			else //du lieu hop le ktra pham vi gia tri
			if (minx <= input and input <max)
			{//trong khoang quy dinh
				check = true;
				cout << "Hop le\n";
			}
			else //vuot pham vi
			{
				check = false;
				cout << "Ban phai nhap gia tri trong khoang " << minx << " va " << max << endl;
			}
			fflush(stdin);
			//flushall();
			//break;
		}
		while(!check);
	return input;//tra ve ket qua hop le
}

Cái nay đang định thắc mắc thì tìm được cách fix luôn mà xóa post thì hơi tiếc nên đăng bài luôn =))

2 Likes

Bad design. Global context mà để user phải tự reset error flag như thế này là chết rồi :smiley:.

2 ví dụ khác (personal experience)

  • Windows API / Unices cũng vớ vẩn tương tự, caller set lỗi mà user không kịp consume lỗi (::GetLastError()/errno), nhảy qua call khác nó overwrite error flag. Và đặt trong loop mà không reset thì cũng bị infinite loop như iostream.
  • OpenGL cũng chơi trò global error flag, nhưng sau mỗi lần consume error (glGetError()), flag sẽ được reset về 0, tránh infinite loop. Ví dụ sau sẽ chỉ chạy 1 lần:
const auto bytes = ::glGetString(0x12345); // ::glGetError() sẽ được set sau call này
while (::glGetError())
{
  ...
  /* driver sẽ reset error flag */
}
4 Likes

Cũng mới tập tễnh nhập môn thôi mà bác.Còn phải học nhiều.=))

1 Like

À, ý là nói cin ấy, không phải code của bạn.

4 Likes

Câu này không hợp lệ đâu, vì flush input stream.

2 Likes
83% thành viên diễn đàn không hỏi bài tập, còn bạn thì sao?