8.7 Con trỏ trỏ đến con trỏ Thursday, September 21, 2017 7:47 PM
Được cắt từ: https://cpp.daynhauhoc.com/8/7-con-tr-tr-den-con-tr/
Trong bài học này, chúng ta sẽ cùng nhau tìm hiểu một khái niệm nâng cao của con trỏ: "Con trỏ trỏ đến con tro"
Pointer to poiïinter là một loại con trỏ dùng để lưu trữ địa chỉ của biến con trỏ
Minh lẫy ví dụ về việc sử dụng con trỏ thông thường: int value;
int *ptr = &value;
Chúng ta gán được địa chỉ của biến value cho con tro ptr vi bién value la
bien kiéu int, va su dung toan tu address-of cho bién value sé tra ve gia
trị kiểu (int *) giống với kiểu dữ liệu cua con tro ptr
Trang 2Như chúng ta thấy, chúng ta cần khai báo biến có kiểu dữ liệu (int **) để có thể gán địa chỉ của con trỏ kiểu (int *) cho nó Let's try:
int *ptr = NULL; int **p to_p = &ptr;
Con trỏ p_to_p được gọi là một Pointer to pointer
Cũng tương tự như khi sử dụng con trỏ thông thường, chúng ta có thể sử dụng toán tử dereference cho một Pointer to pointer
int main() {
int value = 100;
int *ptr = &value; int **p to_p = &ptr;
cout << p to p << endl; //print address of ptr
cout << *p to_p << endl; //print address which hold by ptr cout << **p to_p << endl; //print value at address which hold by ptr
return 0;
}
Bản chất của Pointer to pointer vẫn là một pointer, nên khi truy xuất giá trị của p_to_p chúng ta lấy được địa chỉ mà nó trỏ đến (địa chỉ của biến ptr)
p_to_p; //la &ptr
Khi chung ta su’ dung 1 toan tt dereference cho 1 pointer to pointer, cũng đồng nghĩa chúng ta dang truy xuất đến giá trị tại địa chỉ mà con trỏ ptr nằm giữ (địa chỉ đang được lưu trữ trong biến ptr)
*p to_p; //la ptr
Va khi st? dung 2 toan tt’ dereference cho 1 pointer to pointer, c6 thé viết lại như sau:
*(*p top); //là *ptr
Chúng ta có thể thấy việc sử dụng pointer to pointer cũng tương tự như việc đi hỏi tìm một người bạn mà không biết nhà nó ở đâu, chỉ biết nhà của những người biết vê nó Vậy là chúng ta đi hỏi từng người một
Vi du chung ta la A, dang can gap C nhưng không biết nó ở đâu, chúng ta hỏi (sử dụng toán tử dereference) chú B thì chú B bảo đến địa chỉ mà C đang ở, chúng ta đến địa chỉ mà chú B nắm giữ và truy xuất vào đó là sẽ
tìm được thẳng C
Tóm tắt lại ví dụ trên, chúng ta có thể viết:
A giữ địa chỉ nhà chú B => A = &B;
Trang 3Nhu vay:
(*A) tuong duong (*(&B)) tuong duong &C; *(*A) tương đương *(*(&B)) tương đương C; Áp dụng lại cho ví dụ: int main() { int value = 100; int *ptr = &value; int **p to _p = &ptr;
cout << p_ top << endl; //print address of ptr
cout << *p to_p << endl; //print address which hold by ptr cout << **p to_p << endl; //print value at address which hold by ptr
return 0;
}
Chung ta co thé viét:
p to p giữ địa chỉ của ptr => p_to p = &ptr;
ptr gif dia chi cua value => ptr = &value; Nhu vay:
(*p_to_p) tương duong ptr tuong đương &value;
**b_to p tương đương *#ptr tương đương value; Kết quả: **p to p *p to TP p_to TP a “ak &ptr &value | 100 |
Chúng ta không thể gán trực tiếp như sau:
int **p to_p = &&value; //not valid
Trang 4Và cũng tương tự như những con trỏ khác, Pointer to pointer có thể gán giá trị NULL: int **p to_p = NULL; Array of pointers Pointer to pointer có thể được dùng để quản lý mảng một chiều kiểu con trỏ (int *[]) Ví dụ: int main() { int *p1 = NULL; int *p2 = NULL; int *p3 = NULL; int *p[] = { p1, p2, p3 }; int **p to_p = p; return 0; }
Trong trường hợp này, p_to_p[0] tương đương với p[0]
Thông thường, chúng ta sẽ sử dụng pointer to pointer để quản lý vùng nhớ được cấp phát trên Heap cho mảng một chiêu chứa các con trỏ int *p1 = NULL; int *p2 = NULL; int *p3 = NULL; int **p to_p = new int*[3]; p_to_p[9] = p1; p_to_p[1] = p2; p_to_p[2] = p3; delete[] p_to p;
Tương tự như con trỏ kiểu (int *) dùng để trỏ đến mảng các phần tử kiểu int, con trỏ kiểu (int **) dùng để trỏ đến mảng các phần tử kiểu (¡int *)
2D dynamically allocated array
Một cách sử dụng khác của Pointer to pointer la dung dé quan ly mang hai chiêu được cấp phát trén Heap
Với mảng hai chiêu cấp phát trên Stack, chúng ta chỉ cần khai báo như
sau:
int arr2D[5][19];
Nhưng với mảng hai chiều cấp phát trên Heap sẽ rắc rối hơn
Trang 5chiêu có cùng kích thước Chúng ta cũng đã biết cách cấp phát vùng nhớ cho mảng một chiều trên Heap bằng cách dùng toán tử new đi kèm với toán tử [ ] Ví dụ:
int *arr1 = new int[10]; int *arr2 = new int[10];
h=
Như vậy, một mảng các con trỏ được dùng để quản lý tập hợp các mảng một chiêu này sẽ tạo thành mảng 2 chiều Ví dụ:
int *pToArrPtr[3];
for(int i = 0; 1 < 3; i++)
{ }
Kết quả của đoạn chương trình này cho chúng ta một vùng nhớ có kích
thước (3 x 5) phần tử kiểu int Và chúng ta có thể truy xuất từng giá trị
thông qua con trỏ pToArrPtr:
Trang 6C:\WINDOWS\system32\cmd.exe — T x
Kết quả hoàn toàn giống với mảng hai chiêu thông thường Nhưng lúc
này, 3 con trỏ pToArrPtr[0] và pToArrPtr[ 1 | và pToArrPtr|2] van là biến được cấp phát trên Stack Để chuyển những con trỏ quản lý các mảng
một chiêu con này sang Heap, chúng ta cần sử dụng Pointer to pointer Dưới đây là toàn bộ chương trình mẫu cho việc cấp phát và giải phóng
vùng nhớ 2 chiêu hoạt động tương tự như mảng hai chiều thông thường:
†include <1ostream>
using namespace std; int main() {
int **pToArrPtr;
//Cấp phát vùng nhớ cho 3 con trỏ kiểu (int *)
pToArrPtr = new int*[3];
//Mỗi con trỏ kiểu (int *) sẽ quản lý 5 phần tử kiểu int
Trang 7for (int i = 0; i < 3; i++) { for (int j = 0; j < 5; j++) { cout << pToArrPtr[i|[j] << " "3 } cout << endl; } //Giai phóng vùng nhớ cho từng dãy vùng nhớ mà 3 con trỏ đang quản lý for (int 1 = 6; 1 < 3; i++) { delete[ ] pToArrPtr[i]; } //Giải phóng cho 3 biến con trỏ chịu sự quản lý của pToArrPtr delete[ ] pToArrPtr; return 0; }
Pointer to pointer to pointer to
Chúng ta có thể khai báo những con trỏ có dạng như sau:
int ***ptrX3;
int ******ptrX6G;
Tuy nhiên, việc thao tác với những con trỏ như thế này khá phức tạp và rất ít gặp trong thực tế nên mình không đề cập trong bài học này
Tổng kết
Pointer to pointer là một phần nâng cao của con trỏ Việc thao tác cấp phát và giải phóng vùng nhớ khá phức tạp Do đó, các bạn mới học có thể hoàn toàn bỏ qua bài học này Mình cũng khuyên các bạn nên tránh sử dụng Pointer to pointer trừ khi không còn giải pháp nào thay thế 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