Chi tiết bài học Con trỏ trong C++

Con trỏ trong C++

Trong bài này, bạn sẽ được học tất cả mọi thứ về con trỏ. Bạn sẽ được học cách giá trị được lưu trong máy tính và cách truy xuất chúng dựa vào con trỏ.

Con trỏ là tính năng rất mạnh mẽ của C++ giúp nó khác biệt với các ngôn ngữ khác như Java hay Python.

Con trỏ được sử dụng trong chương trình C++ để truy xuất vào bộ nhớ và thao tác với địa chỉ.

Địa chỉ trong C++

Để hiểu rõ hơn về con trỏ, đầu tiên bạn cần hiểu cách dữ liệu được lưu trong máy tính.

Mỗi biến bạn tạo trong chương trình được gán một địa chỉ trong vùng nhớ của máy tính. Giá trị lưu mà biến lưu trữ trên thực tế được lưu tại địa chỉ được gán.

Để biết nơi dữ liệu được lưu, C++ có toán tử &. Toán tử & (tham chiếu) trả về cho bạn địa chỉ được cấp cho một biến.

Nếu var là một biến thì &var sẽ trả về địa chỉ của biến đó.

Ví dụ 1: Địa chỉ trong C++

#include <iostream>
using namespace std;

int main()
{
    int var1 = 3;
    int var2 = 24;
    int var3 = 17;
    cout << &var1 << endl;
    cout << &var2 << endl;
    cout << &var3 << endl;
}

Đầu ra

0x7fff5fbff8ac

0x7fff5fbff8a8

0x7fff5fbff8a4

Chú ý: Bạn không thể có cùng kết quả trên hệ thống của mình.

Giá trị 0x ở vị trí đầu tiên biểu diễn địa chỉ ở dạng số hexa.

Chú ý rằng địa chỉ đầu tiên lệch 4 bytes so với địa chỉ thứ 2 và địa chỉ thứ 2 lệch 4 bytes so với địa chỉ thứ 3.

Đó là do kích thước của biến int (biến kiểu int) là 4 bytes trên hệ thống 64-bit

Biến con trỏ

C++ cho phép bạn thao tác với dữ liệu trong vùng nhớ máy tính một cách trực tiếp. Bạn có thể gán, thu hồi bất cứ vùng nhớ nào trong bộ nhớ như bạn muốn. Điều này được thực hiện thông qua biến con trỏ.

Biến con trỏ là các biến trỏ tới một địa chỉ nhất định trong vùng nhớ đã được trỏ bởi một biến khác.

Cách khai báo một con trỏ?

int *p;
      hoặc,
int* p;

Câu lệnh trên định nghĩa một biến con trỏ p. Nó chứa địa chỉ vùng nhớ.

Dấu sao là toán tử giúp truy cập vào vùng nhớ, hay nghĩa là trỏ tới.

Ở đây, con trỏ p là một con trỏ trỏ tới int, nghĩa là nó trỏ tới một giá trị số nguyên trong địa chỉ vùng nhớ.

Toán tử tham chiếu (&) và toán tử trỏ tới (*)

Toán tử tham chiếu (&) như đưa ra ở trên sẽ trả về địa chỉ của một biến.

Để lấy giá trị lưu trong địa chỉ vùng nhớ, chúng ta cần sử dụng toán tử truy cập (*).

Ví dụ: Nếu biến number được lưu trong vùng nhớ có địa chỉ 0x123, và nó chứa giá trị 5.

Toán tử tham chiếu (&) sẽ trả về giá trị 0x123 trong khi toán tử trỏ tới (*) sẽ trả về giá trị 5.

Chú ý: Ký hiệu (*) được dùng trong khai báo con trỏ trong C++ không phải là con trỏ truy cập. Đó chỉ là ký hiệu tương đồng được dùng để tạo một con trỏ.

Ví dụ 2: Con trỏ trong C++

Chương trình C++ biểu diễn cách hoạt động của con trỏ

#include <iostream>
using namespace std;
int main() {
    int *pc, c;
    
    c = 5;
    cout << "Address of c (&c): " << &c << endl;
    cout << "Value of c (c): " << c << endl << endl;

    pc = &c;    // con trỏ pc chứa địa chỉ ô nhớ của biến c
    cout << "Address that pointer pc holds (pc): "<< pc << endl;
    cout << "Content of the address pointer pc holds (*pc): " << *pc << endl << endl;
    
    c = 11;    // Giá trị chứa trong địa chỉ vùng nhớ &c được chuyển từ 5 thành 11.
    cout << "Address pointer pc holds (pc): " << pc << endl;
    cout << "Content of the address pointer pc holds (*pc): " << *pc << endl << endl;

    *pc = 2; 
    cout << "Address of c (&c): " << &c << endl;
    cout << "Value of c (c): " << c << endl << endl;

    return 0;
}

Đầu ra

Address of c (&c): 0x7fff5fbff80c

Value of c (c): 5

 

Address that pointer pc holds (pc): 0x7fff5fbff80c

Content of the address pointer pc holds (*pc): 5

 

Address pointer pc holds (pc): 0x7fff5fbff80c

Content of the address pointer pc holds (*pc): 11

 

Address of c (&c): 0x7fff5fbff80c

Value of c (c): 2

Giải thích chương trình

  • Khi

    c = 5;

    giá trị 5 được lưu trong địa chỉ của biến

    c

    – 0x7fff5fbff8c.

  • Khi

    pc = &c;

    con trỏ pc sẽ trỏ tới địa chỉ của

    c

    – 0x7fff5fbff8c, và biểu thức (toán tử trỏ tới) *pc sẽ cho ra giá trị được lưu tại địa chỉ đó, tức là 5.

  • Khi

    c = 11;

    vì địa chỉ con trỏ

    pc

    vẫn đang trỏ tới

    c

    – 0x7fff5fbff8c, nên khi thay đổi giá trị của c cũng ảnh hưởng tới kết quả khi thực thi biểu thức

    *pc

    , và giờ sẽ cho ra kết quả là 11.

  • Khi

    *pc = 2;

    nó sẽ thay đổi nội dung của vùng nhớ được lưu bởi

    pc

    – 0x7fff5fbff8c. Nó sẽ thay đổi giá trị từ 11 thành 2. Vì thế khi chúng ta in ra giá trị của

    c

    , kết quả vẫn là 2.

Lỗi thường gặp khi làm việc với con trỏ

Giả sử bạn muốn con trỏ pc trỏ tới địa chỉ của c. Khi đó,

int c, *pc;
pc=c;  /* Sai! pc là địa chỉ, c không phải là địa chỉ */
*pc=&c; /* Sai! *pc là giá trị được trỏ tới, trong khi đó, &c là một địa chỉ. */
pc=&c; /* Đúng! pc là một địa chỉ và &c cũng là một địa chỉ. */
*pc=c; /* Đúng! *pc là giá trị được trỏ tới bởi địa chỉ và c cũng là một giá trị. */

Trong cả hai trường hợp, con trỏ pc đang không trỏ tới địa chỉ của c.