Buffer là gì?
Buffer (bộ đệm) là vùng nhớ tạm thời lưu trữ dữ liệu khi chuyển giữa chương trình và thiết bị I/O (bàn phím, màn hình, file, network). Giúp giảm số lần truy cập thiết bị chậm.
Loại Buffer
| Loại | Mô tả | Ví dụ |
|---|---|---|
| Input Buffer | Lưu dữ liệu từ bàn phím/file trước khi chương trình đọc | stdin buffer |
| Output Buffer | Lưu dữ liệu chương trình ghi, chờ đẩy ra màn hình/file | stdout buffer |
| File Buffer | Buffer riêng cho mỗi FILE* | fopen() tạo buffer |
Chế độ Buffer của stdout
- Line buffered: Flush khi gặp '\n' (mặc định terminal)
- Fully buffered: Flush khi buffer đầy (mặc định file, pipe)
- Unbuffered: Ghi ngay lập tức (stderr mặc định)
Ví dụ hiện tượng Buffer
#include <stdio.h>
int main() {
int a, b;
printf("Nhap a: ");
scanf("%d", &a); // Nhập: "1 2 3" + Enter
printf("Nhap b: ");
scanf("%d", &b); // Không chờ nhập, lấy "2" từ buffer!
printf("a=%d, b=%d, tong=%d\n", a, b, a+b);
return 0;
}
Kết quả
Nhap a: 1 2 3
Nhap b: a=1, b=2, tong=3
→ scanf("%d", &b) lấy "2" còn sót trong buffer sau lần nhập đầu.
Xử lý Buffer - Các hàm
| Hàm | Header | Chức năng |
|---|---|---|
fflush(stdout) | stdio.h | Xả buffer xuất (ép in ra màn hình ngay) |
fflush(stdin) | stdio.h | Xóa buffer nhập (KHÔNG CHUẨN C - chỉ Windows/MSVC) |
flushall() | conio.h | Xóa tất cả buffer (Chỉ Turbo C/DOS, không chuẩn) |
setbuf(fp, NULL) | stdio.h | Tắt buffer cho file |
setvbuf() | stdio.h | Cấu hình buffer tùy chỉnh |
Cách xóa Input Buffer chuẩn C (Portable)
// Cách 1: Đọc và bỏ qua đến newline
void xoaBuffer() {
int c;
while ((c = getchar()) != '\n' && c != EOF);
}
// Cách 2: Dùng scanf với %*c (bỏ qua 1 ký tự)
scanf("%d%*c", &a); // Đọc số, bỏ qua 1 ký tự (thường là \n)
// Cách 3: Dùng fgets + sscanf (khuyên dùng nhất)
char buf[100];
fgets(buf, sizeof(buf), stdin);
sscanf(buf, "%d", &a);
Chương trình demo fflush(stdout)
#include <stdio.h>
#include <unistd.h> // sleep()
int main() {
printf("Dang tai");
fflush(stdout); // Buộc in ngay "Dang tai"
sleep(1);
printf("."); fflush(stdout);
sleep(1);
printf("."); fflush(stdout);
sleep(1);
printf(". Hoan tat!\n");
return 0;
}
Kết quả
In từng dấu chấm cách 1 giây (không có fflush thì in hết một lần sau 3 giây).
Buffer và scanf/fgets conflit
// Vấn đề: scanf để lại '\n' trong buffer
int n;
char s[100];
scanf("%d", &n); // Nhập: 5 + Enter → buffer còn '\n'
fgets(s, 100, stdin); // Đọc ngay '\n' → chuỗi rỗng!
// Sửa: Xóa buffer sau scanf
scanf("%d", &n);
while (getchar() != '\n'); // Xóa đến hết dòng
fgets(s, 100, stdin); // Đọc bình thường
Tóm tắt Best Practice
- Dùng
fgets()+sscanf()cho mọi nhập liệu (tránh buffer issue) - Dùng
fflush(stdout)khi in prompt không có '\n' - KHÔNG dùng
fflush(stdin),flushall()(không chuẩn) - Hiểu rõ: scanf để lại whitespace trong buffer
- File I/O: fclose() tự flush, nhưng fflush(fp) an toàn hơn trước khi đọc lại file vừa ghi