Thận trọng: fflush(stdin);
có thể là hành vi không xác định. Đọc: Why fflush(stdin)
is wrong?
int fflush(FILE *ostream);
Các ostream
điểm để một output stream hoặc một dòng cập nhật trong đó hoạt động gần đây nhất là không đầu vào, các fflush
chức năng gây ra bất kỳ dữ liệu bất thành văn cho dòng đó sẽ được chuyển giao đến môi trường máy chủ để được ghi vào tệp; nếu không, số behavior
là Undefined
.
Bạn có thể thử một vòng lặp và đọc cho đến khi EOF
hoặc \n
cho this FAQ entry thay vì fflush(stdin)
như tôi đã gợi ý dưới đây trong câu trả lời của tôi.
Edit: nhờ @Jonathan Leffler:
Có nền tảng nơi fflush(stdin)
là hoàn toàn được xác định (như là một phần mở rộng phi tiêu chuẩn trên nền tảng đó). Ví dụ chính là một hệ thống các hệ thống nổi tiếng được gọi chung là Windows. Đặc điểm kỹ thuật của Microsoft về int fflush(FILE *stream);
Nếu số stream
mở để nhập, fflush
xóa nội dung của bộ đệm.
Tôi có thêm sự nghi ngờ trong mã của bạn; M
trong biểu thức unsigned int b = pow(2,M-1);
là gì? Nó sẽ là một lỗi nếu bạn không xác định nó. Bạn có đăng mã hoàn chỉnh không?
Về bạn logic của phát hiện lỗi:
đọc lại giá trị nếu người dùng nhập vào một hợp lệ
Không, scanf()
không trả lại một mã lỗi. Nó trả về số lượng chuyển đổi thành công.
int scanf (const char * format, ...);
Return Value
Mở thành công, hàm trả về số lượng các mục của danh sách đối số đầy thành công.Số này có thể khớp với số số lượng dự kiến hoặc ít hơn (thậm chí là 0) do lỗi khớp, lỗi đọc hoặc phạm vi tiếp cận của tệp kết thúc.
Nếu một lỗi xảy ra đọc hoặc file end-of-đạt được trong khi đọc, chỉ số thích hợp được thiết lập (feof
hoặc ferror
). Và nếu xảy ra trước khi có thể đọc thành công bất kỳ dữ liệu nào, thì trả lại EOF
.
Nếu lỗi mã hóa diễn giải các ký tự rộng, đặt chức năng errno
đến EILSEQ
.
Vì vậy, thực sự tùy thuộc vào lỗi gặp phải giá trị trả về có thể bằng không, EOF. Bạn nên sử dụng macro int ferror (FILE * stream);
và errno
để phát hiện lỗi (kiểm tra ví dụ được đưa ra tại liên kết).
lỗi có thể vì đầu vào không hợp lệ có thể là:
EILSEQ
: Input chuỗi byte không tạo thành một ký tự hợp lệ.
EINVAL
: Không đủ đối số; hoặc định dạng là NULL.
ERANGE
: Một chuyển đổi số nguyên sẽ vượt quá kích thước có thể được lưu trữ trong loại số nguyên tương ứng.
Kiểm tra scanf manual để biết danh sách đầy đủ.
Lý do vòng lặp vô hạn:
Hệ thống theo dõi trong đó đầu vào đã được nhìn thấy cho đến nay. Mọi cuộc gọi đến số scanf
đều được chọn từ nơi người cuối cùng ngừng nhập dữ liệu khớp. Điều này có nghĩa là nếu xảy ra lỗi với scanf
trước đó, thông tin nhập không khớp với vẫn chưa được đọc, như thể người dùng đã nhập trước. Nếu cẩn thận không được thực hiện để loại bỏ lỗi đầu vào, và một vòng lặp được sử dụng để đọc đầu vào, chương trình của bạn có thể bị bắt trong một vòng lặp vô hạn.
Vì vậy, ví dụ như trong mã của bạn:
x = scanf("%u", &a);
// ^
// need a number to be input
Nhưng giả sử bạn không nhập vào một số nhưng một chuỗi không hợp lệ được nhập ví dụ "name"
(thay vì một số, như bạn nói). Điều này sẽ làm cho hàm scanf()
bị lỗi khi cố gắng khớp một số nguyên không dấu ("%u"
) và từ "name"
chưa được đọc. Vì vậy, lần sau thông qua vòng lặp, các scanf()
không chờ đợi cho đầu vào người dùng mới, nó cố gắng để chuyển đổi "tên" một lần nữa.
Tương tự, nếu đầu vào là 29.67
, các "%u
" sẽ phù hợp với chỉ hai nhân vật đầu tiên (29
), rời khỏi .67
đầu vào là chưa đọc cho cuộc gọi tiếp theo để scanf()
.
Ngay cả khi đầu vào là chính xác, như 29
, dòng mới đã kết thúc dữ liệu nhập vẫn chưa đọc.Thông thường, đó không phải là vấn đề vì hầu hết các chuyển đổi tự động bỏ qua không gian trắng hàng đầu, chẳng hạn như dấu dòng mới từ dòng trước đó. Tuy nhiên một số chuyển đổi ("%c"
và "%["
) không bỏ qua bất kỳ khoảng trống trắng nào, vì vậy bạn phải thực hiện theo cách thủ công.
Để tránh vô hạn vòng lặp này Một gợi ý:
(hãy nhớ rằng: khi tôi khuyến cáo việc sử dụng ferror()
, lỗi có giá trị là một lợi thế để phát hiện đầu vào không hợp lệ Thêm vào đó, nó chỉ cho mục đích học tập và nếu bạn. cần phải thực hiện một ứng dụng nghiêm trọng bạn nên sử dụng fgets(str)
thay vì scanf()
sau đó phân tích str
đầu vào để xác minh xem đầu vào là hợp lệ)
input:
//fflush(stdout); //use if needed, as \n used in printf no need of fflush-stdout
printf("\nEnter any integer: ");
x = scanf("%u", &a); // always wait for new symbols
printf("%u", a);
if(x == 0){ // x=0, if error occurred
// read all unread chars
while ((ch = getchar()) != '\n' && ch != EOF);
goto input;
}
Nó chỉ là một ý kiến cho rằng sẽ p ossibly làm việc với mã của bạn (làm việc cho tôi, mã của bạn + gcc). Nhưng nếu bạn sử dụng kỹ thuật này không chính xác nó có thể để lại một lỗi trong mã của bạn:
đọc How do I flush the input buffer?
Nếu bạn chắc chắn rằng dữ liệu không mong muốn là trong dòng đầu vào, bạn có thể sử dụng một số đoạn mã sau các đoạn trích để xóa chúng. Tuy nhiên, nếu bạn gọi những điều này khi không có dữ liệu trong luồng đầu vào, chương trình sẽ đợi cho đến khi có, cho bạn kết quả không mong muốn.
bạn có thể sử dụng làm vòng lặp while trong trường hợp này. Vui lòng xem mã sửa đổi được đưa ra dưới đây – stev