Sunday, April 24, 2016

New, Malloc và Calloc để tạo mảng động

* new, malloc có thể được dùng với những công dụng khác, trong bài này chỉ nói đến việc sử dụng để tạo mảng động.

1. Malloc

void* malloc(size_t size);
malloc là phương thức để xin cấp phát một vùng nhớ trên heap. Hàm malloc nhận vào kích thước của vùng nhớ cần cấp phát(tính theo byte) và trả về con trỏ void.
Vì thế để tạo mảng động với malloc ta phải tính ra kích thước vùng nhớ của mảng cần tạo. Sử dụng sizeof để lấy kích thước kiểu dữ liệu của phần tử trong mảng rồi nhân với độ dài mảng.

int* arr = (int*)malloc(sizeof(int) * 10);
Trong đoạn code trên, ta tạo mảng có độ dài 10 phần tử. Hàm malloc trả về con trỏ void nên ta phải ép kiểu(cast) về kiểu dữ liệu của phần tử trong mảng. Trường hợp không còn bộ nhớ hợp lệ để cập phát, hàm malloc sẽ trả về 0. Trường hợp tạo thành công hàm trả về con trỏ trỏ đến vùng nhớ mới được cấp phát, và trong vung nhớ này chứa toàn giá trị rác(junk memory).
2. Calloc

void* calloc(size_t num, size_t size);
Hàm calloc để xin cấp phát một vùng nhớ và reset vùng nhớ bằng giá trị 0. Tham số num là số phần tử của mảng, size là kích thước kiểu dữ liệu của mỗi phần tử.
Cũng như hàm malloc, hàm calloc cũng xin cấp phát một vùng nhớ trên heap. Nhưng trong hầu hết các trường hợp, sau khi tao xong vùng nhớ ta đều gán một giá trị khởi tạo cho vùng nhớ đó thường là giá trị 0, để tránh vùng nhớ chứa giá trị rác. Hàm calloc tương đương với khởi tạo vùng nhớ malloc rồi reset vùng nhớ bằng memset
3. New
Operator new cũng được dùng để khởi tạo mảng động. Khác với malloc, toán tử new tự động tính kích thước kiểu dữ liệu của phần tử, và trả về con trỏ đã được ép kiểu. Hàm malloc sau khi cấp phát vùng nhớ xong, vùng nhớ vẫn chứa giá trị rác, nhưng với toán tử new, sau khi cấp phát mỗi phần tử sẽ được gọi constructor mặc định của nó.
4. Xóa mảng
Mảng động được tạo ra nhưng không được tự động hủy(Hệ điều hành thu hồi lại) nên ta phải gọi hàm hủy.
Nếu dùng malloc hay calloc để cấp phát thì hủy bằng hàm free, nếu dùng new để cấp phát thì dùng delete[].
+ Hàm free nhận vào con trỏ void, và k0 cần ép kiểu hay truyền vào kich thước. Hàm free chỉ trả lại vùng nhớ nhưng con trỏ vẫn còn chì đến vị trí vùng nhớ đó. Con trỏ này được gọi stray pointer, tức là con trỏ trỏ đế vùng nhớ rác, vì thế sau khi goi free thì nên gán con trỏ về 0.
+ Toán tử delete[] để xóa mảng và gọi destructor của mổi phần tử trước khi thực thi. Lưu ý: phải có dấu [] nếu không chỉ có phần tử đầu tiên được xóa và bị leak memory. Sử dụng delete[] để xóa cũng nên gán con trỏ về lai 0.

int* arr1 = (int*)malloc(sizeof(int) * 10);
int* arr2 = new int[10];
---
free(arr1);
arr1 = 0;
delete[] arr2;
arr2 = 0;
* Việc sử dụng malloc hay new để tạo mảng tùy thuộc vào người dùng. Hàm malloc cấp phát bộ nhớ nhanh, toán tử new cấp phát chậm hơn nhưng an toàn(đảm bảo các phần tử đều được khởi tạo bằng default constructor).