Quản lý bộ nhớ động trong C, C++
Trong bài học này, bạn sẽ cấp phát một mảng có kích thước xác định khi chạy chương trình và giải phóng vùng nhớ đó một cách an toàn.
Giới thiệu
Bộ nhớ động được dùng khi kích thước hoặc thời gian tồn tại của dữ liệu không thể xác định lúc biên dịch, ví dụ khi số phần tử phụ thuộc vào dữ liệu người dùng nhập vào. Vùng nhớ này được cấp phát trong lúc chương trình chạy và phải được giải phóng khi không còn dùng đến.
Những điểm quan trọng
- Con trỏ chỉ được trỏ tới đối tượng còn tồn tại, đúng kiểu dữ liệu, hoặc mang giá trị null.
- Mỗi vùng nhớ được cấp phát chỉ được giải phóng đúng một lần.
- Thể hiện rõ hàm nào sở hữu vùng nhớ (ownership) và dữ liệu nào chỉ được đọc (const).
Code ví dụ bằng C và C++
#include <stdio.h>
#include <stdlib.h>
int main(void) {
size_t count = 5;
int *values = calloc(count, sizeof *values);
if (!values) return 1;
for (size_t i = 0; i < count; ++i) values[i] = (int)(i * i);
printf("last=%d\n", values[count - 1]);
free(values);
return 0;
}
last=16
#include <iostream>
#include <vector>
int main() {
std::vector<int> values(5);
for (std::size_t i = 0; i < values.size(); ++i) values[i] = static_cast<int>(i * i);
std::cout << "last=" << values.back() << '\n';
}
last=16
So sánh C và C++
Trong C, calloc cấp phát vùng nhớ cho 5 số nguyên và khởi tạo chúng bằng 0. Chương trình phải kiểm tra việc cấp phát có thất bại hay không và gọi free để giải phóng khi dùng xong, nếu quên sẽ gây rò rỉ bộ nhớ (memory leak). Trong C++, std::vector tự quản lý vùng nhớ của nó và tự giải phóng khi không còn được dùng, kể cả khi có ngoại lệ xảy ra.
Việc sở hữu và giải phóng vùng nhớ hoàn toàn do lập trình viên tự đảm bảo.
Container và RAII tự động giải phóng tài nguyên khi đối tượng hết thời gian tồn tại.
Bài tập mở rộng
Hãy chạy cả hai phiên bản, sau đó thử thay đổi code để quan sát sự khác biệt về mức độ an toàn mà mỗi ngôn ngữ mang lại.
- Thử với con trỏ null và trường hợp cấp phát bộ nhớ thất bại.
- Chạy chương trình với AddressSanitizer và UndefinedBehaviorSanitizer để phát hiện lỗi bộ nhớ.
- Ghi chú rõ con trỏ nào sở hữu vùng nhớ và con trỏ nào chỉ dùng để đọc.
Luyện tập với thử thách
Áp dụng kiến thức của bài học này để giải một bài toán thực tế. Mỗi thử thách chạy ngay trên trình duyệt, có kiểm thử tức thì và AI nhận xét.
Tất cả thử thách