Con trỏ hằng (const pointer)
Từ khóa const có thể kết hợp với con trỏ theo nhiều cách khác nhau, mỗi cách mang một ý nghĩa riêng. Đây là chủ đề khiến nhiều người mới học C++ bối rối, nhưng chỉ cần nhớ một quy tắc đơn giản: const áp dụng cho phần đứng ngay bên trái nó.
1. Con trỏ trỏ đến giá trị hằng (pointer to const)
Phần tiêu đề “1. Con trỏ trỏ đến giá trị hằng (pointer to const)”Giá trị tại địa chỉ mà con trỏ trỏ đến không thể bị thay đổi thông qua con trỏ này - nhưng bản thân con trỏ vẫn có thể trỏ sang địa chỉ khác:
#include <iostream>
int main() { int x = 10; int y = 20;
const int* ptr = &x; // "con trỏ trỏ đến một int hằng"
// *ptr = 100; // LỖI! Không thể thay đổi giá trị thông qua ptr ptr = &y; // OK - ptr có thể trỏ sang biến khác std::cout << *ptr << std::endl; // 20
return 0;}2. Con trỏ hằng (const pointer)
Phần tiêu đề “2. Con trỏ hằng (const pointer)”Ngược lại, con trỏ không thể trỏ sang địa chỉ khác sau khi khởi tạo - nhưng giá trị tại địa chỉ đó vẫn có thể thay đổi:
#include <iostream>
int main() { int x = 10; int y = 20;
int* const ptr = &x; // "con trỏ hằng, trỏ đến một int"
*ptr = 100; // OK - có thể thay đổi giá trị tại địa chỉ ptr đang trỏ // ptr = &y; // LỖI! Không thể đổi hướng trỏ của một con trỏ hằng
std::cout << x << std::endl; // 100
return 0;}3. Con trỏ hằng trỏ đến giá trị hằng
Phần tiêu đề “3. Con trỏ hằng trỏ đến giá trị hằng”Kết hợp cả hai: vừa không thể đổi hướng trỏ, vừa không thể thay đổi giá trị tại đó:
int x = 10;const int* const ptr = &x; // Cả con trỏ VÀ giá trị đều là hằng
// *ptr = 100; // LỖI!// ptr = &y; // LỖI!
std::cout << *ptr << std::endl; // 10 - chỉ có thể đọcGhi nhớ: đọc từ phải sang trái
Phần tiêu đề “Ghi nhớ: đọc từ phải sang trái”Một mẹo hữu ích để phân biệt các khai báo trên: đọc khai báo từ tên biến, lùi dần sang trái:
| Khai báo | Đọc là | Ý nghĩa |
|---|---|---|
int* ptr |
“ptr là con trỏ đến int” | Con trỏ bình thường |
const int* ptr |
“ptr là con trỏ đến int hằng” | Không đổi được giá trị |
int* const ptr |
“ptr là con trỏ hằng, đến int” | Không đổi được hướng trỏ |
const int* const ptr |
“ptr là con trỏ hằng, đến int hằng” | Không đổi được cả hai |
Ứng dụng thực tế: tham số hàm
Phần tiêu đề “Ứng dụng thực tế: tham số hàm”Cách dùng const với con trỏ phổ biến nhất là trong tham số hàm, để đảm bảo hàm không vô tình sửa đổi dữ liệu được trỏ đến:
#include <iostream>
void print_value(const int* ptr) { std::cout << *ptr << std::endl; // *ptr = 100; // LỖI! Hàm này chỉ được phép đọc, không được sửa}
int main() { int x = 42; print_value(&x); return 0;}Tổng kết
Phần tiêu đề “Tổng kết”const int* ptr: giá trị tại địa chỉ trỏ đến không thể sửa, nhưng con trỏ có thể đổi hướngint* const ptr: con trỏ không thể đổi hướng, nhưng giá trị tại đó vẫn sửa đượcconst int* const ptr: cả hai đều không thể thay đổi- Dùng
constvới con trỏ trong tham số hàm là cách phổ biến để đảm bảo hàm không sửa đổi dữ liệu ngoài ý muốn