Sử dụng hàm freopen() trong thư viện
Trong khóa học, chúng ta đã thường nhập dữ liệu từ bàn phím và xuất kết quả trên cửa sổ console. Tuy nhiên, trong một số kỳ thi lập trình và công việc lập trình sau này, việc nhập dữ liệu từ file trở nên phổ biến. May mắn là ngôn ngữ C/ c+ + cung cấp những cú pháp đơn giản để thực hiện việc nhập và xuất dữ liệu bằng file.
1. Sử dụng hàm freopen() trong thư viện
Với người dùng editor Code::Blocks, đặc biệt là trong lĩnh vực lập trình thi đấu, hàm freopen() là một công cụ tiện lợi để nhập và xuất dữ liệu bằng file. Cú pháp sử dụng như sau:
freopen("Tên_file", "Định_dạng_nhập_xuất", Luồng_vào_ra);
Hàm này thường được sử dụng ở ngay đầu hàm main() của chương trình. Để hiểu rõ hơn về các đối số của hàm, chúng ta hãy phân tích từng phần:
-
Tên_file
: Đây là tên của file dữ liệu được sử dụng để nhập và xuất dữ liệu. Tên file có thể có nhiều phần mở rộng khác nhau, như .inp, .out, .dat, .in, .ou,... Tùy thuộc vào yêu cầu bài toán mà chúng ta sử dụng phần mở rộng tương ứng. -
Định_dạng_nhập_xuất
: Đây là một chữ cái để xác định file dữ liệu được sử dụng cho mục đích nhập hay xuất. Có 555 định dạng nhập xuất đa dạng, nhưng trong lập trình thi đấu, chúng ta thường chỉ quan tâm đến hai định dạng "r" (read - đọc) và "w" (write - ghi). -
Luồng_vào_ra
: Đây là luồng dữ liệu được sử dụng, có thể là luồng đầu vào (stdin) hoặc luồng đầu ra (stdout).
Ví dụ minh họa:
#include #include using namespace std; int main() { freopen("Chinhphuong.inp", "r", stdin); freopen("Chinhphuong.out", "w", stdout); int N; cin >> N; for (int i = 1; i = N; ++i) cin >> a[i]; // Các câu lệnh khác trong chương trình có thể tiếp tục... }
2. Sử dụng các kiểu dữ liệu ifstream, ostream và fstream trong thư viện
2.1. Khai báo các file input và output
Ngoài cách sử dụng freopen(), C++ còn cung cấp ba lớp để hỗ trợ đọc và ghi dữ liệu từ file:
-
ifstream
: Sử dụng để đọc dữ liệu từ file. -
ofstream
: Sử dụng để ghi dữ liệu ra file. -
fstream
: Sử dụng để đọc và ghi dữ liệu bằng file.
Để sử dụng các lớp này, chúng ta cần khai báo hai thư viện:
ifstream Tên_biến_file_input; ofstream Tên_biến_file_output; fstream Tên_biến_file_vừa_input_vừa_output;
Ví dụ, khai báo ba biến kiểm soát file input và output như sau:
ifstream input_file; // File để đọc dữ liệu vào. ofstream output_file; // File để ghi dữ liệu ra. fstream io_file; // File để vừa đọc vừa ghi dữ liệu.
2.2. Mở một file để làm việc
Sau khi đã khai báo các đối tượng file, chúng ta cần mở file để thực hiện đọc và ghi dữ liệu. Để làm điều này, chúng ta sử dụng cú pháp:
Tên_biến_file.open("Tên_file_cần_mở", Chế_độ_mở);
Trong đó, Tên_biến_file
là tên biến mà chúng ta đã khai báo để kiểm soát file, "Tên_file_cần_mở"
là tên file trong máy tính mà chúng ta muốn sử dụng, và Chế_độ_mở
là lựa chọn để mở file và làm gì với nó. Có một số chế độ mở file phổ biến, chẳng hạn:
ios::in
- Mở file để đọc.ios::out
- Mở file để ghi.ios::app
- Mở file để ghi tiếp vào cuối file.ios::trunc
- Xóa nội dung file nếu file đã tồn tại.ios::binary
- Mở file dưới dạng binary.
Ví dụ, để mở một file có tên "sample_input.inp" để đọc dữ liệu:
input_file.open("sample_input.inp", ios::in);
2.3. Thao tác đọc và ghi dữ liệu bằng file
Sau khi đã mở một file thành công, chúng ta có thể đọc và ghi dữ liệu bằng file đó bằng cách sử dụng toán tử và
>>
, giống như toán tử cin
và cout
khi nhập và xuất dữ liệu từ luồng chuẩn. Cú pháp như sau:
Tên_biến_file_input >> Tên_biến_nhập_vào; Tên_biến_file_output Dữ_liệu_xuất_ra;
Các quy tắc nhập xuất dữ liệu tương tự như khi sử dụng cin
và cout
. Nếu muốn tìm hiểu chi tiết hơn về các thao tác trong nhập xuất dữ liệu bằng fstream, bạn có thể đọc thêm tại đây.
2.4. Đóng file sau khi sử dụng
Trong lập trình thi đấu, việc đóng file sau khi đọc và ghi dữ liệu thường không cần thiết, vì các dữ liệu chỉ được đọc và ghi một lần duy nhất trong quá trình chạy chương trình. Tuy nhiên, trong các dự án lớn, việc đóng file sau khi hoàn thành việc đọc và ghi dữ liệu là cần thiết để bảo toàn dữ liệu của file và cho phép file được sử dụng trong các tiến trình khác. Để đóng file, chúng ta sử dụng cú pháp:
Tên_biến_file.close();
Tóm lại, đọc và ghi dữ liệu bằng file có thể được thực hiện theo hai cách. Tuy nhiên, đối với lập trình thi đấu, việc sử dụng hàm freopen() được ưa thích hơn vì đơn giản và dễ nhớ.
Kĩ năng debug code trên Code::Blocks
Trong quá trình lập trình, chúng ta thường gặp những test cases sai mặc dù chương trình vẫn chạy được, cho ra kết quả không đúng. Để giải quyết vấn đề này, kĩ năng debug code là rất quan trọng. Để sử dụng tính năng debug code, chúng ta nên sử dụng cách nhập và xuất dữ liệu từ file để thuận tiện hơn trong quá trình nhập liệu.
Quy trình debug code sẽ diễn ra qua các bước sau:
-
Mở project chứa bài toán cần debug lên, kèm theo file .cpp chứa code, file .inp và .out để đọc và ghi dữ liệu.
-
Đặt con trỏ chuột vào vị trí mà bạn muốn bắt đầu quá trình debug, rồi nhấn
F4
(có thể phải nhấn tổ hợpFn - F4
). Một hình tam giác màu vàng sẽ hiện ra tại vị trí bắt đầu debug. -
Chọn thẻ
Debug
->Debugging windows
->Watches
để bật chế độ quan sát các biến. -
Khung cửa sổ
Watches
sẽ hiện ra, chúng ta có thể điều chỉnh kích thước theo ý muốn. Con trỏ chuột cần được đặt vào màn hình code để tiếp tục debug. Trong khung hình, các biến đã được khai báo sẽ hiển thị ở mụcLocals
. Nếu muốn xem thêm các biến toàn cục, ta có thể thêm nó vào khungWatches
. -
Tiến hành debug bằng cách nhấn phím
F7
để chạy từng câu lệnh. Khi hình tam giác màu vàng chạy tới dòng nào, các biến trong khungWatches
sẽ tự động thay đổi theo logic thuật toán đã viết. -
Để kết thúc quá trình debug, ta nhấn vào dấu x màu đỏ trên thanh công cụ.
Nếu trong chương trình có thêm các hàm và bạn muốn debug cả trong hàm, hãy nhấn tổ hợp phím Shift-F7
để tiến vào hàm và tiếp tục debug các câu lệnh trong hàm.
Đó là kĩ năng debug cơ bản. Hy vọng rằng việc sử dụng nhập và xuất dữ liệu từ file sẽ giúp bạn trong quá trình debug code.
Tác giả: Vũ Quế Lâm từ Viblo