Computer >> Hướng Dẫn Máy Tính >  >> Lập Trình >> Lập Trình C

Buffer (Bộ đệm) trong C: Đầu vào/đầu ra và xử lý

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 BufferLưu dữ liệu từ bàn phím/file trước khi chương trình đọcstdin buffer
Output BufferLưu dữ liệu chương trình ghi, chờ đẩy ra màn hình/filestdout buffer
File BufferBuffer 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.hXả buffer xuất (ép in ra màn hình ngay)
fflush(stdin)stdio.hXóa buffer nhập (KHÔNG CHUẨN C - chỉ Windows/MSVC)
flushall()conio.hXóa tất cả buffer (Chỉ Turbo C/DOS, không chuẩn)
setbuf(fp, NULL)stdio.hTắt buffer cho file
setvbuf()stdio.hCấ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

  1. Dùng fgets() + sscanf() cho mọi nhập liệu (tránh buffer issue)
  2. Dùng fflush(stdout) khi in prompt không có '\n'
  3. KHÔNG dùng fflush(stdin), flushall() (không chuẩn)
  4. Hiểu rõ: scanf để lại whitespace trong buffer
  5. 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