Xin chào mọi người!
Ở bài trước mình đã giới thiệu tổng quát về Con trỏ trong C++ rồi Mình muốn các bạn hiểu thật sâu về con trỏ nên nếu ai đọc qua về con trỏ thì vào đây (Con trỏ Phần 1) để xem nhé!
3. Lấy giá trị con trỏ
Mọi biến, hằng trong C++ đều có địa chỉ riêng của nó. Hình dưới đây thể hiện rõ điều này
Biến val trong hình có giá trị bằng 5, nhưng đồng thời nó cũng lưu địa chỉ của nó trong bộ nhớ RAM là 0xFE, sau đó ta khởi tạo 1 con trỏ ptr và giá trị của nó chính là địa chỉ của biến val (0xFE). Ta gọi con trỏ ptr đang “trỏ” tới biến val.
Để lấy địa chỉ của một biến, hằng trong C++, ta chỉ việc thêm dấu & trước tên biến, hằng. Ở hình trên, con trỏ ptr trỏ tới biến val bằng cách ghi&val.
Vậy, sau khi trỏ vào rồi, ta làm gì với con trỏ đây?
Lúc này, con trỏ ptr cũng giống như biến val. Ta thao tác với biến val như thế nào, con trỏ ptr cũng bị tác động như thế đấy, và ngược lại. Ví dụ:
1
2
3
4
5
| int val = 5; int *ptr = &val; *ptr = 6; cout << val; // = 6??? |
Ở ví dụ trên, mình muốn lưu ý với các bạn 1 điều, ptr lưu giữ địa chỉ của biến val, nên nếu muốn truy xuất tới giá trị mà ptr trỏ tới, ta cần phải thêm toán tử * vào trước tên con trỏ. Với val++ tương đương với (*p)++ (cần thiết phải có dấu ngoặc tròn, vì toán tử ++ có độ ưu tiên thấp hơn*, với lại nhìn cũng sáng sủa, dễ hiểu hơn :D).
4. Kiểu dữ liệu con trỏ
Với các biến thường, ta có những kiểu như int, long, double, char,… Cũng tương tự, con trỏ cũng có kiểu dữ liệu int*, long*, double*, char*,… Con trỏ chỉ được phép trỏ tới biến cùng kiểu dữ liệu, trừ con trỏ void (chỉ trỏ lung tung thế thì bất lịch sự lắm :v).
Tuy có nhiều kiểu dữ liệu cho con trỏ như thế, nhưng bất kỳ con trỏ nào cũng đều có kích thước 4 byte. Nghe thì hơi ngộ nhưng nếu các bạn chịu khó suy nghĩ thì sẽ thấy rất bình thường :D. Giá trị của con trỏ đều là địa chỉ của biến nó trỏ đến, cho nên dù là con trỏ kiểu gì thì nó cũng chỉ chứa giá trị địa chỉ thôi (nếu các bạn muốn kiểm chứng, sử dụng hàm sizeof() mà mình đã giới thiệu ở Bài 2 – Kiểu dữ liệu, biến và hằng trong C++).
Giả sử như chúng ta có 3 biến kiểu int, long, char. Nếu muốn sử dụng con trỏ để trỏ tới 3 biến này, theo lý thuyết ta phải dùng tới 3 con trỏ kiểu int*, long* và char*. Vậy có cách nào tối ưu hơn không?
Trong C++ có hỗ trợ 1 kiểu dữ liệu đặc biệt dành cho con trỏ, đó là con trỏ void. Nó có thể trỏ tới mọi biến, dù cho các biến khác kiểu dữ liệu. Tuy nhiên, có 1 lưu ý dành cho con trỏ void, mình xin đưa ra ví dụ sau:
1
2
3
4
| int a = 10; void *pVoid = &a; // Con trỏ void pVoid trỏ vào biến a int *p = pVoid; // Lỗi cout << *p << endl; |
Ớ ví dụ trên, con trỏ p muốn trỏ tới biến a, nên nó gán giá trị bằng pVoid (vì con trỏ pVoid đang trỏ đến biến a). Tuy nhiên vì con trỏ void không biết kiểu dữ liệu của nó trỏ đến là gì, cho nên trình biên dịch sẽ báo lỗi khi gán 2 con trỏ khác kiểu dữ liệu. Để khắc phục điều này, ta cần phảiép kiểu:
1
2
3
4
| int a = 10; void *pVoid = &a; // Con trỏ void pVoid trỏ vào biến a int *p = ( int *)pVoid; // Ép kiểu int* cout << *p << endl; |
Lúc này trình biên dịch sẽ chạy hoàn toàn bình thường. Cần lưu ý khi sử dụng con trỏ void nhé
Bản thân mình biết về con trỏ cũng không nhiều, nên mình chỉ viết theo những gì mình biết. Nếu có điều gì sai sót, mong các bạn comment phía bên dưới, mình sẽ chỉnh sửa lại trong thời gian ngắn nhất! Con trỏ về lý thuyết còn rất nhiều, mình sẽ đề cập nó sau, ở trong bài Mảng và Chuỗi
Trên đây là bài viết về Con trỏ – Phần 2. Cảm ơn các bạn đã chú ý theo dõi!
Bình Luận:
0 bình luận: