1. Con trỏ trỏ đến các biến hằng

Tính đến thời điểm này, tất cả các con trỏ mà bạn đã được thấy đều là các con trỏ không hằng (non-const pointer) trỏ đến các giá trị không phải là hằng số (non-const values):

/**
* Cafedev.vn - Kênh thông tin IT hàng đầu Việt Nam
*
* @author cafedevn
* Contact: cafedevn@gmail.com
* Fanpage: https://www.facebook.com/cafedevn
* Instagram: https://instagram.com/cafedevn
* Twitter: https://twitter.com/CafedeVn
* Linkedin: https://www.linkedin.com/in/cafe-dev-407054199/
*/

int value = 5;
int *ptr = &value;
*ptr = 6; // change value to 6

Tuy nhiên, điều gì sẽ xảy ra nếu giá trị là hằng số?

const int value = 5; // value is const
int *ptr = &value; // compile error: cannot convert const int* to int*
*ptr = 6; // change value to 6

Đoạn code trên sẽ không thể biên dịch được – chúng ta không thể gán một giá trị hằng số cho một con trỏ không hằng (non-const pointer). Điều này thật sự có ý nghĩa: Một biến hằng số là biến mà giá trị của nó không thể thay đổi được. Giả sử, nếu chúng ta có thể gán một giá trị hằng số cho một con trỏ không hằng, vậy thì sau đó chúng ta cũng có thể dereference con trỏ không hằng này và thay đổi giá trị. Điều này sẽ vi phạm khái niệm về giá trị hằng.

2. Con trỏ trỏ đến giá trị hằng

Một con trỏ trỏ đến một giá trị hằng là một con trỏ không hằng (non-constant pointer) mà trỏ đến một giá trị hằng.

Để khai báo một con trỏ trỏ đến một giá trị hằng, sử dụng từ khóa const trước kiểu dữ liệu:

const int value = 5;
const int *ptr = &value; // this is okay, ptr is a non-const pointer that is pointing to a "const int"
*ptr = 6; // not allowed, we can't change a const value

Trong ví dụ trên, ptr trỏ đến một giá trị hằng kiểu int.

Rất dễ hiểu phải không? Bây giờ xét ví dụ sau:

int value = 5; // value is not constant
const int *ptr = &value; // this is still okay

Một con trỏ trỏ đến một biến hằng có thể trỏ đến một biến không hằng (non-constant variable) (chẳng hạn như biến value trong ví dụ trên). Có thể hiểu điều trên như sau: Một con trỏ trỏ đến một biến hằng sẽ coi biến này là hằng khi nó được truy cập thông qua con trỏ, bất kể biến này ban đầu có được định nghĩa là hằng hay không.

Do đó, đoạn code sau sẽ đúng:

int value = 5;
const int *ptr = &value; // ptr points to a "const int"
value = 6; // the value is non-const when accessed through a non-const identifier

Nhưng đoạn code này sẽ sai:

int value = 5;
const int *ptr = &value; // ptr points to a "const int"
*ptr = 6; // ptr treats its value as const, so changing the value through ptr is not legal

Bởi vì bản thân một con trỏ trỏ đến một giá trị hằng, không phải là hằng (nó chỉ trỏ đến một giá trị hằng), cho nên con trỏ này có thể được chuyển hướng để trỏ đến các giá trị khác:

/**
* Cafedev.vn - Kênh thông tin IT hàng đầu Việt Nam
*
* @author cafedevn
* Contact: cafedevn@gmail.com
* Fanpage: https://www.facebook.com/cafedevn
* Instagram: https://instagram.com/cafedevn
* Twitter: https://twitter.com/CafedeVn
* Linkedin: https://www.linkedin.com/in/cafe-dev-407054199/
*/

int value1 = 5;
const int *ptr = &value1; // ptr points to a const int
 
int value2 = 6;
ptr = &value2; // okay, ptr now points at some other const int

3. Con trỏ hằng

 Chúng ta cũng có thể làm cho một con trỏ trở thành hằng. Một con trỏ hằng là một con trỏ mà giá trị của nó không thể được thay đổi sau khi khởi tạo.

Để khai báo một con trỏ hằng, sử dụng từ khóa const giữa dấu hoa thị và tên con trỏ:

int value = 5;
int *const ptr = &value;

Giống như một biến hằng bình thường, một con trỏ hằng phải được khởi tạo với một giá trị khi khai báo. Điều này có nghĩa là một con trỏ hằng sẽ luôn luôn trỏ đến một địa chỉ duy nhất. Trong ví dụ trên, ptr luôn luôn trỏ đến địa chỉ của biến value (cho đến khi ptr bị đi ra khỏi phạm vi của đoạn code mà chương trình đang chạy và bị hủy).

/**
* Cafedev.vn - Kênh thông tin IT hàng đầu Việt Nam
*
* @author cafedevn
* Contact: cafedevn@gmail.com
* Fanpage: https://www.facebook.com/cafedevn
* Instagram: https://instagram.com/cafedevn
* Twitter: https://twitter.com/CafedeVn
* Linkedin: https://www.linkedin.com/in/cafe-dev-407054199/
*/

int value1 = 5;
int value2 = 6;
 
int * const ptr = &value1; // okay, the const pointer is initialized to the address of value1
ptr = &value2; // not okay, once initialized, a const pointer can not be changed.

Xét ví dụ sau, bởi vì biến value đang được trỏ tới không phải là một biến hằng, nên ta có thể thay đổi giá trị đang được trỏ đến (ý là giá trị của biến value) bằng cách dereferencing con trỏ hằng:

int value = 5;
int *const ptr = &value; // ptr will always point to value
*ptr = 6; // allowed, since ptr points to a non-const int

4. Con trỏ hằng trỏ đến một giá trị hằng

Cuối cùng, chúng ta cũng có thể khai báo một con trỏ hằng trỏ đến một giá trị hằng bằng cách đặt từ khóa const trước kiểu dữ liệu và trước tên biến:

int value = 5;
const int *const ptr = &value;

Một con trỏ hằng trỏ đến một giá trị hằng không thể được thiết lập để trỏ đến một địa chỉ khác, đồng thời giá trị mà con trỏ này đang trỏ tới cũng không thể thay đổi được thông qua con trỏ này. 

5. Tóm tắt

Để tóm tắt lại, bạn chỉ cần nhớ 4 quy tắc sau, và chúng khá logic:

  • Một con trỏ không hằng có thể được chuyển hướng để trỏ  tới các địa chỉ khác.
  • Một con trỏ hằng luôn luôn trỏ tới một địa chỉ duy nhất, và địa chỉ này không thể được thay đổi.
  • Một con trỏ trỏ đến một giá trị không phải là hằng, có thể thay đổi được giá trị mà nó đang trỏ tới. Những con trỏ kiểu này thì không thể trỏ đến một giá trị hằng.
  • Một con trỏ trỏ đến một giá trị hằng sẽ coi giá trị này như là một hằng số (kể cả khi giá trị này không phải là hằng số), và do đó không thể thay đổi được giá trị mà nó đang trỏ tới.

Việc giữ các cú pháp khai báo luôn luôn đúng có thể là một thử thách khi mới làm quen, tuy nhiên, bạn chỉ cần nhớ rằng kiểu dữ liệu của giá trị mà con trỏ sẽ trỏ đến, luôn luôn nằm ở phía ngoài cùng bên trái khi khai báo.

6. Tổng kết

Các con trỏ trỏ tới các giá trị hằng chủ yếu được sử dụng trong các tham số truyền vào của hàm (ví dụ, khi truyền một mảng cho một hàm) để giúp đảm bảo rằng hàm sẽ không vô tình thay đổi đối số được truyền vào trong hàm. Chúng ta sẽ thảo luận thêm về điều này trong các bài học về phần hàm (functions).

Đăng ký kênh youtube để ủng hộ Cafedev nha các bạn, Thanks you!

1 BÌNH LUẬN

Bình luận bị đóng.