Con trỏ kiểu void

Chào các bạn đang theo dõi khóa học lập trình trực tuyến ngôn ngữ C++.

Void pointers

Con trỏ kiểu void, có thể gọi là con trỏ tổng quát, là một kiểu dữ liệu đặc biệt của con trỏ. Con trỏ kiểu void có thể trỏ đến bất kỳ đối tượng nào (với bất kỳ kiểu dữ liệu nào) có địa chỉ cụ thể trên bộ nhớ ảo. Cách khai báo con trỏ kiểu void cũng giống với các con trỏ có kiểu dữ liệu được xây dựng sẵn:

void *ptr; // ptr is a void pointer

Bây giờ, mình có thể gán địa chỉ của các biến có kiểu dữ liệu khác nhau cho con trỏ ptr:

	void *ptr;

	int iValue;
	float fValue;
	double dValue;
	string str;
	int iArr[10];
	
	ptr = &iValue;
	ptr = &fValue;
	ptr = &dValue;
	ptr = &str;
	ptr = iArr;

Chúng ta còn có thể cho con trỏ void trỏ đến những con trỏ khác:

void *ptr;

int *iArr = new int[10];
ptr = iArr;

delete[] iArr;

Cũng như mọi kiểu con trỏ khác, con trỏ kiểu void cũng có kích thước 4 bytes khi chạy trên nền tảng 32 bits, hoặc 8 bytes nếu chạy trên nền tàng 64 bits. Tuy nhiên, con trỏ kiểu void không xác định được kiểu dữ liệu của vùng nhớ mà nó trỏ tới, chúng ta không thể truy xuất trực tiếp nội dung thông qua toán tử dereference được. Do đó, con trỏ kiểu void cần phải được ép kiểu một cách rõ ràng sang con trỏ có kiểu dữ liệu khác trước khi sử dụng toán tử dereference cho vùng nhớ mà con trỏ đang nắm giữ.

Ví dụ:

int value = 5;
void *vPtr = &value;

int *iPtr = static_cast<int *> (vPtr);
cout << *iPtr << endl;

Lúc này, vPtr và iPtr đều trỏ vào địa chỉ của biến value, nhưng chúng ta chỉ có thể sử dụng toán tử dereference lên con trỏ iPtr chứ không thể sử dụng cho con trỏ vPtr.

Điều gì xảy ra nếu chúng ta ép sai kiểu dữ liệu?

Thử với ví dụ sau:

int value = 5;
void *vPtr = &value;

int *iPtr = static_cast<int *> (vPtr);
cout << *iPtr << endl;

int64_t * i64Ptr = static_cast<int64_t *> (vPtr);
cout << *i64Ptr << endl;

Kết quả:

5
-5233161171908952059

Như các bạn thấy, sử dụng sai kiểu dữ liệu đi kèm với đó là kết quả không mong muốn. Do đó, chúng ta nên hạn chế sử dụng con trỏ kiểu void.

Vậy chúng ta sử dụng con trỏ kiểu void cho mục đích gì?

Chúng ta thường sử dụng con trỏ kiểu void khi mà dữ liệu bên trong vùng nhớ đó không quan trọng. Ví dụ mình muốn copy dữ liệu từ dãy vùng nhớ này sang dãy vùng nhớ khác mà không cần quan tâm định dạng của chúng.

Ví dụ:

void *ptr = operator new (100);

Dòng lệnh trên sử dụng toán tử new để cấp phát 100 bytes trên Heap partition và lưu địa chỉ của vùng nhớ đó bên trong con trỏ ptr.

Con trỏ void cũng thường được sử dụng làm tham số của hàm khi muốn input của hàm là con trỏ có kiểu dữ liệu bất kỳ. Chúng ta sẽ tìm hiểu vấn đề này trong những bài học tiếp theo.

Việc giải phóng một vùng nhớ trên Heap bằng tên con trỏ kiểu void cũng có thể gây ra lỗi vì hệ điều hành không tính được kích thước vùng nhớ cần thu hồi là bao nhiêu.


Tổng kết

Trên thực tế, chúng ta nên tránh sử dụng con trỏ kiểu void trừ những lúc thực sự cần thiết để tránh gây ra những sai sót không đáng có cho chương trình.


Hẹn gặp lại các bạn trong bài học tiếp theo trong khóa học lập trình C++ hướng thực hành.

Mọi ý kiến đóng góp hoặc thắc mắc có thể đặt câu hỏi trực tiếp tại diễn đàn.

www.daynhauhoc.com


Link Videos khóa học

https://www.udemy.com/c-co-ban-danh-cho-nguoi-moi-hoc-lap-trinh/learn/v4/overview

7 Likes

Do đó, chúng ta không nên hạn chế sử dụng con trỏ kiểu void.

Đọc câu này làm mình bối rối quá

Nếu dùng không nên thì bỏ hạn chế đi chứ, viết vậy làm mình nghiệm hoài không hiểu

Con trỏ void dùng để “hiện thực” generic function trong C. Có thể dùng cài đặt mem pool.

Anh có thể ví dụ giúp em cái này được ko ạ? Nếu ko dereference được thì làm sao copy dữ liẹu vùng này sang vùng khác được ạ?

Từ void* đổi qua char* không có gì đáng ngại. Con trỏ void xuất hiện ngay trong prototype đơn giản là vì việc ép kiểu sang void* là tự động.

83% thành viên diễn đàn không hỏi bài tập, còn bạn thì sao?