23/12/2018, 23:14

[C++] Bản chất con trỏ

Khái niệm con trỏ là gì? Nếu bạn là coder sử dụng C#, java, Object C, Swift ... thì có thể bỏ qua bài này nhưng nếu bạn là code C++ hoặc nếu thích thì có thể tham khảo và cho mình xin ý kiến. Bài này mình sẽ đề cập đến một vấn đề khá phức tạp nhưng lại có rất nhiếu ý nghĩa trong lập trình ...

  1. Khái niệm con trỏ là gì?

Nếu bạn là coder sử dụng C#, java, Object C, Swift ... thì có thể bỏ qua bài này nhưng nếu bạn là code C++ hoặc nếu thích thì có thể tham khảo và cho mình xin ý kiến.

Bài này mình sẽ đề cập đến một vấn đề khá phức tạp nhưng lại có rất nhiếu ý nghĩa trong lập trình C++. Nó cũng là nguyên nhân của rất nhiều vấn đề trong lập trình C++. Đó chính là con trỏ.


Theo định nghĩa:

In computer science, a pointer is a programming language object that stores the memory address of another value located in computer memory. [Wikipedia]


Dịch: Trong khoa học máy tính, một con trỏ là một đối tượng lập trình, nó lưu địa chỉ ô nhớ của một ô nhớ chưa giá trị khác trong máy tính.

Để đơn giản, các bạn hãy hiểu rằng: Mỗi một ô nhớ trong máy tính là một căn nhà. Thường thì mỗi nhà sẽ có một địa chỉ nhà riêng biệt gồm số nhà, xã, huyện, tỉnh tương ứng. Và số nhà này được ghi trong một cuốn sổ của của phòng địa chính từng vùng. Vậy thì, cuốn sổ ghi địa chỉ mỗi căn hộ tương ứng chính là một con trỏ, nó lưu địa chỉ căn nhà mà chúng ta đang đề cập đến.
  1. Ví dụ và phân tích

Đầu tiên chúng ta sẽ xét đoạn code dưới đây

int main()
{
    /*Poiter ==> address / reference / variable ==> Value*/
    int a = 5;
    int *p_a = &a;

    cout << "Value kept by variable a is    : " << a << endl;
    cout << "Address of variable a is       : " << &a << endl;

    cout << "Value kept by poiter p_a is    : " << *p_a << endl;
    cout << "Reference kept by poiter p_a is: " << p_a << endl;
    cout << "Address of poiter p_a is       : " << &p_a << endl;
}

Kết quả sẽ in ra:

Value kept by variable a is : 5

Address of variable a is : 0x7ffeef3e431c

Value kept by poiter p_a is : 5

Reference kept by poiter p_a is: 0x7ffeef3e431c

Address of poiter p_a is : 0x7ffeef3e4320

Bạn có thấy gì đặc biệt trong đoạn code ví dụ trên không, kết quả in ra:

Address of variable a is : 0x7ffeef3e431c

Reference kept by poiter p_a is: 0x7ffeef3e431c

Hay là *p_a = &a Chắc chắn các bạn sẽ thắc mắc, thế thì có gì đặc biệt, chả phải trong code cũng đã viết int *p_a = &a rồi còn gì. Đúng rồi, vậy các bạn hãy thử thay đổi đoạn code trên thế này xem sao:

int main()
{
    /*Poiter ==> address / reference / variable ==> Value*/
    int a = 5;
    int *p_a = 0x7ffeef3e431c;
}

Build, run and see!! Vâng, các bạn sẽ chẳng thể đến bước run được đâu, bởi vì compiler sẽ không chịu build đoạn code trên cho các bạn. Vì sao? Vì int *p_a là một con trỏ, và nó sẽ chỉ lưu địa chỉ của một biến khác chứ không đơn thuần là một con số như cái mà đoạn code ban đầu đã in ra.

Quay lại ví dụ miếng đất ở mục 1, cuốn sổ của phòng địa chính cũng sẽ phải được lưu ở đâu đó. Khi này, ở trên bộ muốn biết được chỉ nhà, vườn mỗi hộ dân, họ không tội gì lại tạo ra một cuốn sổ khác và lưu hết toàn bộ địa chỉ nhà vườn của tất cả người dân Việt Nam. Họ sẽ tạo ra một cuốn sổ khác và lưu địa chỉ nơi chứa cuốn sổ ban đầu. Đây là ví dụ con trỏ bậc 2.


Trong code sẽ như sau:
int **p_b = &p_a;

Cứ như vậy ta có thể tạo ra con trỏ bậc 3, 4, ..., n. Nhưng mà thôi, bậc 2 cũng đã đủ đau đầu lắm rồi.

  1. Lưu ý khi sử dụng con trỏ.

Có nhiều tài liệu ghi chú vấn đề về việc khởi tạo và hủy đối tượng khi sử dụng con trỏ. Điều này là để chương trình đảm bảo chương trình chạy đúng và không xảy ra những hệ lụy nghiêm trọng khi sử dụng sai.

Trong phần lớn các sự cố, khi sử dụng sai con trỏ chương trình sẽ chỉ hoạt động sai hay là crash app. Khi crash liên quan đến con trỏ, thường các bạn sẽ được gặp một thông báo lỗi trong quá trình debug là SIGSEGV hay Signal 11. Nếu có backtrace, coredump ... các bạn sẽ dễ dàng tìm ra lỗi ở đoạn nào. Tuy nhiên, trong trường hợp nghiêm trọng hơn, lỗi này có thể gây sụp đổ hoàn toàn hệ thống và xóa luôn hệ điều hành khỏi máy tính của bạn             </div>
            
            <div class=

0