Con trỏ trong C là một định nghĩa không còn mới lạ đối với các nhà lập trình viên. Tuy cơ bản mặc dù vậy lĩnh vực kiến thức mà con trỏ trong C++ liên quan là rất rộng. Người sử dụng cần nắm vững những thông tin quan trọng này để có thể sử dụng 1 cách nhuần nhuyễn con trỏ C. Bài đăng sau sẽ nhắc đến khái niệm của con trỏ là gì, cách dùng và biểu diễn nó trong ngôn ngữ lập trình như thế nào. Hãy theo dõi ngay!
1. Khái niệm con trỏ là gì ?
Nhớ lại bộ nhớ lưu giữ biến
RAM chứa rất nhiều ô nhớ, mỗi ô nhớ có kích thước 1 byte.
Mỗi ô nhớ có địa chỉ duy nhất & địa chỉ này được đánh số từ 0 trở đi. Nếu CPU 32 bit thì có 2^32 địa chỉ có thể đánh cho các ô nhớ trong RAM.
Khi khai báo biến, trình biên dịch dành riêng một vùng nhớ với địa chỉ độc nhất để lưu biến. Trình biên dịch có trách nhiệm liên kết địa chỉ ô nhớ đó với tên biến. Khi gọi tên biến, nó sẽ truy xuất tự động đến ô nhớ đã liên kết với tên biến để lấy dữ liệu. Các bạn phải luôn phân biệt giữa địa chỉ bộ nhớ & dữ liệu được lưu trong số đó.
Có thể lấy địa chỉ của một biến bằng cách dùng toán tử và.
int a;
cout <<"Address of a: "<<&a << endl;
Address of a: 00F6FDFC
Địa chỉ của biến bản chất cũng là một con số hay được biểu diễn ở hệ cơ số 16. Ta có thể dùng con trỏ (pointer) để lưu địa chỉ của các biến.
Con trỏ là gì?
Trong ngôn ngữ C++, con trỏ (pointer) là những biến lưu giữ địa chỉ bộ nhớ của những biến khác.
Trong hình trên, biến var lưu giá trị 5 có địa chỉ là 0x61ff08. Biến pointVar là biến con trỏ, lưu địa chỉ của biến var (trỏ đến vùng nhớ của biến var), tức là nó lưu giá trị 0x61ff08.
2. Cách khai báo con trỏ
Con trỏ trong C cũng có thể khai báo kiểu như biến thông thường.
<kiểu dữ liệu>*<tên biến>
Trong đó:
· Kiểu dữ liệu có thể là: void, char, int, float, double,…
· Dấu * trước tên biến là ký hiệu báo cho trình biên dịch biết ta đang khai báo con trỏ.
Ví dụ:
int *p; // khai báo con trỏ để trỏ tới biến kiểu nguyên// khai báo con trỏ p kiểu int, biến val (không phải con trỏ) kiểu intint *p, val; float *p; // khai báo con trỏ để trỏ tới biến kiểu thựcchar *p; // khai báo con trỏ để trỏ tới biến kiểu ký tự void *p; // con trỏ kiểu void (không kiểu), đây chính là 1 kiểu đặc biệt của con trỏ. Con trỏ kiểu void có thể trỏ đến bất kỳ đối tượng nào (với bất kỳ kiểu dữ liệu nào) có địa chỉ cụ thể trên bộ nhớ ảo.
Ta xét 1 VD sau:
int *p; // khai báo con trỏ để trỏ tới biến kiểu nguyên
Thì ở đây ta có các đặc trưng của con trỏ p như sau
· Kiểu dữ liệu của con trỏ là kiểu int
· Giá trị của con trỏ ký hiệu p, có thể gán p trỏ tới 1 địa chỉ nào đấy như sau p = 0x7ffd9e4d
· Địa chỉ của con trỏ ký hiệu là &p
· Giá trị của biến nơi con trỏ đang trỏ đến ký hiệu là *p
Lưu ý, kiểu dữ liệu của con trỏ phải trùng với kiểu dữ liệu của biến mà con trỏ trỏ đến.
Ví dụ:
int x = 7; char y = 1;int *pc = &x; // OK vi x có kiểu dữ liệu là intint *pc = &y; // FAIL vi y có kiểu dữ liệu là char
3.Các thao tác trên con trỏ
Gán địa chỉ của biến cho biến con trỏ
Toán tử và dùng để định vị con trỏ đến địa chỉ của một biến đang làm việc.
Cú pháp:=&;
Giải thích: Ta gán địa chỉ của biến “Tên biến” cho con trỏ “Tên biến con trỏ”.
Ví dụ: Gán địa chỉ của biến a cho con trỏ pa, gán địa chỉ của biến b cho con trỏ pb.
pa=&a;
pb=&b;
Lưu ý: Khi gán địa chỉ của biến tĩnh cho con trỏ cần phải chú ý kiểu dữ liệu của chúng.
Ví dụ sau đây không đúng do không tương thích kiểu:
int Bien_Nguyen;
float *Con_Tro_Thuc; …
Con_Tro_Thuc = &Bien_Nguyen;
Phép gán ở đây là sai vì Con_Tro_Thuc là một con trỏ kiểu float (nó chỉ có thể chứa được địa chỉ của biến kiểu float); trong khi đó, Bien_Nguyen có kiểu int.
Nội dung của ô nhớ con trỏ chỉ tới
Để truy cập đến nội dung của ô nhớ mà con trỏ chỉ tới, ta sử dụng cú pháp:
*
VD 3: Ví dụ sau đây cho phép khai báo, gán địa chỉ cũng giống như lấy nội dung vùng nhớ của biến con trỏ:
int i=10; int *pi;
pi=&i;
i=10; // hoặc *pi=10;
Lưu ý: Khi gán địa chỉ của một biến cho một biến con trỏ, mọi sự thay đổi trên nội dung ô nhớ con trỏ chỉ tới sẽ làm giá trị của biến thay đổi theo (thực chất nội dung ô nhớ và biến chỉ là một).
Con trỏ của con trỏ hay con trỏ cấp 2
Khái niệm này nghe có vẻ lằng nhằng thế nhưng thực ra cũng rất đợn giản.
Như phần trước đã nói, con trỏ thực ra cũng là một biến, nó cũng có địa chỉ & giá trị. vì vậy nó cũng sẽ có thể sẽ được gọi từ con trỏ khác. Như sau:
VD:
int main ()
int nha_anh_a = 10;
int *address_A = &nha_anh_a;
int **quan_ly = &address_A;
printf("Dia chi cua nha anh A la: %x\n", &nha_anh_a );
printf("Gia tri cua nha anh A la: %d\n", nha_anh_a );
printf("Gia tri cua con tro address_A la: %x\n", address_A);
**quan_ly = 20;
printf("\n");
printf("Dia chi cua nha anh A la: %x\n", &nha_anh_a );
printf("Gia tri cua nha anh A la: %d\n", nha_anh_a );
printf("Gia tri cua con tro address_A la: %x\n", address_A);
return 0;
Giải thích: Ta khai báo 1 con trỏ bậc 2 với dấu ** , lưu giữ giá trị của biến con trỏ address_A
.
Sau đấy tiến hành thay đổi giá trị của biến mà con trỏ address_A
trỏ tới một cách gián tiếp bằng con trỏ cấp 2 quan_ly
>> Xem thêm Tư duy lập trình là gì? Những điều bạn cần biết
Con trỏ NULL trong C
Có một cách thực hành tốt khi chúng ta gán giá trị NULL cho biến con trở trong trường hợp bạn không có địa chỉ chuẩn xác để được gán. Việc này thường xảy ra trong quá trình khai báo. Một con trỏ được gán giá trị NULL có cách gọi khác là con trỏ null.
Con trỏ null là một hằng số với giá trị 0 được khái niệm trong một số thư viện chuẩn. Xem chương trình dưới đây:
#include
int main ()
int *contro = NULL;
printf("Gia tri cua contro la: %x\n", contro );
return 0;
Biên dịch & chạy chương trình C trên sẽ cho kết quả:
Gia tri cua contro la:
0
>>> Xem thêm: Những cuốn sách lập trình C++ tốt nhất cho các Developer 2020
Kết
Con trỏ trong lập trình là một khái niệm nghe thì có vẻ phức tạp, thế nhưng hãy nghĩ về nó một cách đơn giản nhất. Bạn sẽ thấy nó cũng không rối não như những gì bạn nghĩ. Và tất nhiên phải làm việc nhiều với con trỏ chúng ta mới hiểu rõ tường tận nhất về chúng hay thật sự hiểu được con trỏ là gì ?
Nhật Minh – Tổng hợp và bổ sung
Nguồn: deviot.vn, sinhvientot.net, khuenguyencreator.com, teky.edu.vn
Bình luận về chủ đề post