C++ Con trỏ có ví dụ
Con trỏ là gì?
In C++, một con trỏ trỏ đến một biến chứa địa chỉ của một biến khác. Giống như các biến thông thường, con trỏ có kiểu dữ liệu. Ví dụ: một con trỏ kiểu số nguyên có thể chứa địa chỉ của một biến kiểu số nguyên. Một con trỏ kiểu ký tự có thể chứa địa chỉ của một biến kiểu ký tự.
Bạn sẽ thấy con trỏ là biểu tượng tượng trưng của địa chỉ bộ nhớ. Với con trỏ, các chương trình có thể mô phỏng lệnh gọi theo tham chiếu. Họ cũng có thể tạo và thao tác các cấu trúc dữ liệu động. TRONG C++, một biến con trỏ đề cập đến một biến trỏ đến một địa chỉ cụ thể trong bộ nhớ được trỏ bởi một biến khác.
Địa chỉ ở C++
Hiểu C++ con trỏ, bạn phải hiểu cách máy tính lưu trữ dữ liệu.
Khi bạn tạo một biến trong C++ chương trình, nó được gán một khoảng trống trong bộ nhớ máy tính. Giá trị của biến này được lưu trữ ở vị trí được chỉ định.
Để biết vị trí trong bộ nhớ máy tính nơi dữ liệu được lưu trữ, C++ cung cấp & (tham khảo) toán tử. Toán tử trả về địa chỉ mà một biến chiếm giữ.
Ví dụ: nếu x là một biến, &x trả về địa chỉ của biến.
Cú pháp khai báo con trỏ
Tuyên bố của C++ có cú pháp như sau:
datatype *variable_name;
- Kiểu dữ liệu là kiểu cơ sở của con trỏ phải hợp lệ C++ loại dữ liệu.
- Biến_name phải là tên của biến con trỏ.
- Dấu hoa thị được sử dụng ở trên để khai báo con trỏ cũng tương tự như dấu hoa thị được sử dụng để thực hiện phép nhân. Đó là dấu hoa thị đánh dấu biến là một con trỏ.
Đây là một ví dụ về khai báo con trỏ hợp lệ trong C++:
int *x; // a pointer to integer double *x; // a pointer to double float *x; // a pointer to float char *ch // a pointer to a character
Toán tử tham chiếu (&) và toán tử trì hoãn (*)
Toán tử tham chiếu (&) trả về địa chỉ của biến.
Toán tử quy chiếu (*) giúp chúng ta lấy giá trị đã được lưu trong một địa chỉ bộ nhớ.
Ví dụ:
Nếu chúng ta có một biến có tên num, được lưu ở địa chỉ 0x234 và lưu giá trị 28.
Toán tử tham chiếu (&) sẽ trả về 0x234.
Toán tử quy chiếu (*) sẽ trả về 5.
Ví dụ 1:
#include <iostream> using namespace std; int main() { int x = 27; int *ip; ip = &x; cout << "Value of x is : "; cout << x << endl; cout << "Value of ip is : "; cout << ip<< endl; cout << "Value of *ip is : "; cout << *ip << endl; return 0; }
Đầu ra:
Cách thức hoạt động:
Đây là ảnh chụp màn hình của mã:
Giải thích mã:
- Nhập tệp tiêu đề iostream. Điều này sẽ cho phép chúng tôi sử dụng các hàm được xác định trong tệp tiêu đề mà không gặp lỗi.
- Bao gồm không gian tên std để sử dụng các lớp của nó mà không cần gọi nó.
- Gọi hàm main(). Logic chương trình phải được thêm vào trong phần thân của hàm này. { đánh dấu sự bắt đầu của phần thân hàm.
- Khai báo một biến số nguyên x và gán cho nó giá trị 27.
- Khai báo biến con trỏ *ip.
- Lưu địa chỉ của biến x vào biến con trỏ.
- In một số văn bản trên bảng điều khiển.
- In giá trị của biến x ra màn hình.
- In một số văn bản trên bảng điều khiển.
- In địa chỉ của biến x. Giá trị của địa chỉ được lưu trữ trong biến ip.
- In một số văn bản trên bảng điều khiển.
- Giá trị in được lưu trữ tại địa chỉ của con trỏ.
- Chương trình sẽ trả về giá trị khi thực hiện thành công.
- Phần cuối của hàm main().
Con trỏ và mảng
Mảng và con trỏ hoạt động dựa trên một khái niệm liên quan. Có nhiều điều cần lưu ý khi làm việc với mảng có con trỏ. Bản thân tên mảng biểu thị địa chỉ cơ sở của mảng. Điều này có nghĩa là để gán địa chỉ của một mảng cho một con trỏ, bạn không nên sử dụng ký hiệu (&).
Ví dụ:
p = arr;
Điều trên đúng vì arr đại diện cho địa chỉ của mảng. Đây là một ví dụ khác:
p = &arr;
Ở trên là không chính xác.
Chúng ta có thể ngầm chuyển đổi một mảng thành một con trỏ. Ví dụ:
int arr [20]; int * ip;
Dưới đây là một hoạt động hợp lệ:
ip = arr;
Sau phần khai báo trên, ip và arr sẽ tương đương nhau và chúng sẽ chia sẻ các thuộc tính. Tuy nhiên, một địa chỉ khác có thể được gán cho ip, nhưng chúng ta không thể gán bất cứ thứ gì cho arr.
Ví dụ 2:
Ví dụ này cho thấy cách duyệt một mảng bằng cách sử dụng con trỏ:
#include <iostream> using namespace std; int main() { int *ip; int arr[] = { 10, 34, 13, 76, 5, 46 }; ip = arr; for (int x = 0; x < 6; x++) { cout << *ip << endl; ip++; } return 0; }
Đầu ra:
Đây là ảnh chụp màn hình của mã:
Giải thích mã:
- Khai báo một biến con trỏ số nguyên ip.
- Khai báo một mảng có tên arr và lưu trữ 6 số nguyên vào đó.
- Gán mảng cho ip. IP và arr sẽ trở nên tương đương.
- Tạo một vòng lặp for. Biến vòng lặp x được tạo để lặp qua các phần tử mảng từ chỉ mục 0 đến 5.
- In các giá trị được lưu trữ tại địa chỉ IP của con trỏ. Một giá trị sẽ được trả về cho mỗi lần lặp và sẽ thực hiện tổng cộng 6 lần lặp lại. Cuối cùng là một C++ từ khóa có nghĩa là dòng cuối cùng. Hành động này cho phép bạn di chuyển con trỏ sang dòng tiếp theo sau khi mỗi giá trị được in. Mỗi giá trị sẽ được in trên một dòng riêng.
- Để di chuyển con trỏ tới vị trí int tiếp theo sau mỗi lần lặp.
- Kết thúc vòng lặp for.
- Chương trình phải trả về một cái gì đó sau khi thực hiện thành công.
- Kết thúc phần thân hàm main().
Con trỏ rỗng
Nếu không có địa chỉ chính xác nào được gán thì biến con trỏ có thể được gán NULL. Nó nên được thực hiện trong quá trình khai báo. Con trỏ như vậy được gọi là con trỏ null. Giá trị của nó bằng 0 và được xác định trong nhiều thư viện tiêu chuẩn như iostream.
Ví dụ 3:
#include <iostream> using namespace std; int main() { int *ip = NULL; cout << "Value of ip is: " << ip; return 0; }
Đầu ra:
Đây là ảnh chụp màn hình của mã:
Giải thích mã:
- Khai báo một biến con trỏ ip và gán cho nó giá trị NULL.
- Giá trị in của biến con trỏ ip cùng với một số văn bản trên bảng điều khiển.
- Chương trình phải trả về giá trị sau khi hoàn thành thành công.
- Phần cuối của hàm main().
Con trỏ biến
Với C++, bạn có thể thao tác dữ liệu trực tiếp từ bộ nhớ của máy tính.
Không gian bộ nhớ có thể được chỉ định hoặc chỉ định lại theo ý muốn. Điều này được thực hiện nhờ các biến con trỏ.
Các biến con trỏ trỏ tới một địa chỉ cụ thể trong bộ nhớ của máy tính được trỏ đến bởi một biến khác.
Nó có thể được khai báo như sau:
int *p;
Hoặc,
int* p;
Trong ví dụ của bạn, chúng ta đã khai báo biến con trỏ p.
Nó sẽ giữ một địa chỉ bộ nhớ.
Dấu hoa thị là toán tử quy định có nghĩa là một con trỏ tới.
Con trỏ p đang trỏ đến một giá trị nguyên trong địa chỉ bộ nhớ.
Ví dụ 4:
#include <iostream> using namespace std; int main() { int *p, x = 30; p = &x; cout << "Value of x is: " << *p; return 0; }
Đầu ra:
Đây là ảnh chụp màn hình của mã:
Giải thích mã:
- Khai báo một biến con trỏ p và một biến x có giá trị là 30.
- Gán địa chỉ của biến x cho p.
- In giá trị của biến con trỏ p cùng với một số văn bản trên bảng điều khiển.
- Chương trình phải trả về giá trị sau khi hoàn thành thành công.
- Phần cuối của hàm main().
Ứng dụng của con trỏ
Các chức năng trong C++ chỉ có thể trả về một giá trị. Hơn nữa, tất cả các biến được khai báo trong một hàm đều được phân bổ trên ngăn xếp lệnh gọi hàm. Ngay khi hàm trả về, tất cả các biến ngăn xếp sẽ bị hủy.
Các đối số cho hàm được truyền theo giá trị và bất kỳ sửa đổi nào được thực hiện trên các biến đều không làm thay đổi giá trị của các biến thực tế được truyền. Ví dụ sau giúp minh họa khái niệm này:-
Ví dụ 5:
#include <iostream> using namespace std; void test(int*, int*); int main() { int a = 5, b = 5; cout << "Before changing:" << endl; cout << "a = " << a << endl; cout << "b = " << b << endl; test(&a, &b); cout << "\nAfter changing" << endl; cout << "a = " << a << endl; cout << "b = " << b << endl; return 0; } void test(int* n1, int* n2) { *n1 = 10; *n2 = 11; }
Đầu ra:
Đây là ảnh chụp màn hình của mã:
Giải thích mã:
- Tạo nguyên mẫu của hàm có tên test sẽ nhận hai tham số nguyên.
- Gọi hàm main(). Chúng ta sẽ thêm logic chương trình vào bên trong phần thân của nó.
- Khai báo hai biến số nguyên a và b, mỗi biến có giá trị 5.
- In một số văn bản trên bảng điều khiển. Endl (dòng cuối) sẽ di chuyển con trỏ để bắt đầu in ở dòng tiếp theo.
- In giá trị của biến a trên bảng điều khiển cùng với văn bản khác. Endl (dòng cuối) sẽ di chuyển con trỏ để bắt đầu in ở dòng tiếp theo.
- In giá trị của biến b trên bảng điều khiển cùng với văn bản khác. Endl (dòng cuối) sẽ di chuyển con trỏ để bắt đầu in ở dòng tiếp theo.
- Tạo một hàm có tên test() lấy địa chỉ của biến a và b làm tham số.
- In một số văn bản trên bảng điều khiển. \n sẽ tạo một dòng trống mới trước khi văn bản được in. Endl (dòng cuối) sẽ di chuyển con trỏ để bắt đầu in ở dòng tiếp theo sau khi văn bản được in.
- In giá trị của biến a trên bảng điều khiển cùng với văn bản khác. Endl (dòng cuối) sẽ di chuyển con trỏ để bắt đầu in ở dòng tiếp theo.
- In giá trị của biến b trên bảng điều khiển cùng với văn bản khác. Endl (dòng cuối) sẽ di chuyển con trỏ để bắt đầu in ở dòng tiếp theo.
- Chương trình phải trả về giá trị sau khi hoàn thành thành công.
- Phần cuối của hàm main().
- Xác định hàm test(). Hàm sẽ nhận hai biến con trỏ số nguyên *n1 và *n2.
- Gán biến con trỏ *n1 giá trị 10.
- Gán biến con trỏ *n2 giá trị 11.
- Kết thúc phần thân của hàm test().
Mặc dù, các giá trị mới được gán cho biến a và b bên trong hàm kiểm tra, nhưng sau khi lệnh gọi hàm hoàn thành, giá trị tương tự sẽ không được phản ánh ở hàm main bên ngoài.
Việc sử dụng con trỏ làm đối số hàm giúp truyền địa chỉ thực của biến trong hàm và tất cả những thay đổi được thực hiện trên biến sẽ được phản ánh ở hàm bên ngoài.
Trong trường hợp trên, hàm 'kiểm tra' có địa chỉ của biến 'a' và 'b.' Hai biến này có thể truy cập trực tiếp từ hàm 'test' và do đó, bất kỳ thay đổi nào được thực hiện đối với các biến này đều được phản ánh trong hàm gọi 'main'.
Ưu điểm của việc sử dụng con trỏ
Dưới đây là những ưu/lợi ích của việc sử dụng Con trỏ
- Con trỏ là các biến lưu trữ địa chỉ của đối tượng khác biến trong C++.
- Nhiều biến có thể được sửa đổi và trả về bởi hàm bằng cách sử dụng con trỏ.
- Bộ nhớ có thể được phân bổ động và phân bổ lại bằng cách sử dụng con trỏ.
- Con trỏ giúp đơn giản hóa độ phức tạp của chương trình.
- Tốc độ thực thi của chương trình được cải thiện bằng cách sử dụng con trỏ.
Tổng kết
- Một con trỏ đề cập đến một biến chứa địa chỉ của một biến khác.
- Mỗi con trỏ có một kiểu dữ liệu hợp lệ.
- Con trỏ là biểu tượng tượng trưng của địa chỉ bộ nhớ.
- Con trỏ cho phép các chương trình mô phỏng lệnh gọi theo tham chiếu, tạo và thao tác các cấu trúc dữ liệu động.
- Mảng và con trỏ sử dụng một khái niệm liên quan.
- Tên mảng biểu thị cơ sở của mảng.
- Nếu bạn muốn gán địa chỉ của một mảng cho một con trỏ, đừng sử dụng ký hiệu (&).
- Nếu không có địa chỉ cụ thể để gán một biến con trỏ, hãy gán cho nó một giá trị NULL.