Con Trỏ Trong C++ – Techacademy

Con trỏ trong lập trình là 1 định nghĩa hơi khó nhằn so với những bạn mới học về C + +. Không ngoa khi nói rằng C + + khó vì có con trỏ. Tuy nhiên ví như làm chủ được con trỏ, bạn hoàn toàn có thể hiểu và thao tác với tài liệu trong bộ nhớ máy tính, và những kiến ​ ​ thức tương quan mà bạn học được trải qua con trỏ cũng rất hữu dụng cho việc học những ngôn từ hướng đối tượng người tiêu dùng sau này như Java ví dụ điển hình .Hãy cùng tìm hiểu và khám phá con trỏ trong C + + là gì, quan hệ giữa con trỏ và địa chỉ trong C + +, cấu trúc, vai trò và cách sử dụng con trỏ sau bài học kinh nghiệm này nhé .

I. Khai Báo Con Trỏ Trong C + +

Để khai báo con trỏ trong C + +, chung ta sử dụng với cấu trúc ngữ pháp sau đây :

type *p;

Trong đó type là kiểu dữ liệu của con trỏ, và p là tên con trỏ. Lưu ý là kiểu dữ liệu của con trỏ phải giống với kiểu dữ liệu của dữ liệu cần lưu địa chỉ trong con trỏ.

Ví dụ, tất cả chúng ta khai báo con trỏ tên p với kiểu int như sau :

int *p;

Lưu ý là những cách viết sau đây cũng được gật đầu khi khai báo con trỏ trong C + + :

int* p;
int * p;

Khai BáoKhai Báo Con Trỏ Trong C++Con Trỏ Trong C++

II. Cấp Phát Bộ Nhớ Cho Con Trỏ Trong C + +

Ngôn ngữ C + + tương hỗ ba loại cấp phép bộ nhớ cơ bản, hai loại trong số đó bạn đã được học ở những bài học kinh nghiệm trước :

1. Cấp phát bộ nhớ tĩnh (Static memory allocation):

  • Xảy ra trên các biến tĩnh và biến toàn cục.
  • Vùng nhớ của các loại biến này được cấp phát một lần khi chương trình bắt đầu chạy và vẫn tồn tại trong suốt thời gian tồn tại của chương trình.
  • Kích thước của biến/mảng nên được biết tại thời điểm biên dịch chương trình.

2. Cấp phát bộ nhớ tự động (Automatic memory allocation):

  • Xảy ra trên các tham số hàm và biến cục bộ.
  • Vùng nhớ của các loại biến này được cấp phát khi chương trình đi vào khối lệnh và được giải phóng khi khối lệnh bị thoát.
  • Kích thước của biến/mảng phải được biết tại thời điểm biên dịch chương trình.

3. Cấp phát bộ nhớ động (Dynamic memory allocation) sẽ được kể tới trong bài học này.

Trong toàn bộ những trường hợp, cấp phép bộ nhớ tĩnh và tự động hóa hoàn toàn có thể cung ứng tốt những đề xuất của chương trình. Tuy nhiên, ta cùng xem ví dụ bên dưới :
Ví dụ : Chúng ta cần sử dụng một chuỗi để lưu tên của người dùng, nhưng tất cả chúng ta không biết tên của họ dài bao nhiêu cho đến khi họ nhập tên. Hoặc tất cả chúng ta cần tàng trữ list nhân viên cấp dưới trong một công ty, nhưng tất cả chúng ta không biết trước được công ty đó sẽ có bao nhiêu nhân viên cấp dưới .
Đối với cấp phép bộ nhớ tĩnh và tự động hóa, kích cỡ của biến / mảng phải được biết tại thời gian biên dịch chương trình. Vì vậy, điều tốt nhất tất cả chúng ta hoàn toàn có thể làm là nỗ lực đoán một kích cỡ tối đa của những biến đó :

char name[30]; // tên không quá 30 ký tự
Staff staff[500]; // công ty không quá 500 nhân viên

Khuyết điểm của cách khai báo trên :
+ Gây tiêu tốn lãng phí bộ nhớ nếu những biến không thực sự sử dụng hết size khi khai báo. Ví dụ : nếu công ty chỉ có 100 nhân viên cấp dưới, tất cả chúng ta có 400 vùng nhớ nhân viên cấp dưới không được sử dụng tới .
+ Thứ hai, hầu hết những biến thường thì ( gồm có mảng tĩnh ) được cấp phép trong một phần bộ nhớ gọi là ngăn xếp ( stack ). Kích thước bộ nhớ stack cho một chương trình khá nhỏ ( khoảng chừng 1M b với Visual Studio ), nếu nhu yếu cấp phép vùng nhớ vượt quá số lượng này, chương trình sẽ bị đóng bởi hệ điều hành quản lý với lỗi stack overflow .

char byte[1000000 * 2]; // khoảng 2Mb bộ nhớ => lỗi stack overflow 

+ Thứ ba, điều gì xảy ra nếu công ty có 600 nhân viên cấp dưới, trong khi mảng staff chỉ có 500 thành phần. Lúc này, chương trình sẽ bị số lượng giới hạn bởi kích cỡ được khai báo bắt đầu .
Để xử lý những hạn chế trên, cấp phép bộ nhớ động được sinh ra .
Cấp Phát Bộ Nhớ Cho Con Trỏ Trong C++

III. Con Trỏ Trong C + + Dùng Để Làm Gì

Tác dụng của con trỏ trong c chính là để lưu giữ địa chỉ của tài liệu trong bộ nhớ máy tính, và bằng cách truy vấn vào địa chỉ này, tất cả chúng ta hoàn toàn có thể lấy được giá trị của tài liệu tại đó .
Ngoài ra thì giá trị của con trỏ cũng là 1 số ít, nên tất cả chúng ta cũng hoàn toàn có thể thực thi những phép tính toán với con trỏ, ví dụ như cộng thêm hoặc hoặc trừ đi một số lượng đơn vị chức năng .
Do đó, con trỏ trong C sẽ được dùng để làm 1 trong 2 việc làm sau đây trong chương trình :

  1. Thao tác với địa chỉ bằng các phép tính toán với số được lưu trong nó
  2. Thao tác với giá trị tại địa chỉ mà nó lưu mà thôi.

Con Trỏ Trong C++ Dùng Để Làm Gì

IV. Mảng Con Trỏ Trong C + +

Trước khi tất cả chúng ta hiểu về khái niệm mảng những con trỏ, tất cả chúng ta xem xét ví dụ sau, mà sử dụng một mảng gồm 3 số integer :

#include 
 
using namespace std;
const int MAX = 3;
 
int main ()
{
   int  var[MAX] = {10, 100, 200};
 
   for (int i = 0; i < MAX; i++)
   {
      cout << "Gia tri cua var[" << i << "] = ";
      cout << var[i] << endl;
   }
   return 0;
}

Khi code trên được biên dịch và thực thi, nó cho hiệu quả sau :

Gia tri cua var[0] = 10
Gia tri cua var[1] = 100
Gia tri cua var[2] = 200

Có một trường hợp khi tất cả chúng ta muốn duy trì một mảng, mà hoàn toàn có thể lưu giữ những con trỏ tới một kiểu tài liệu int hoặc char hoặc bất kể kiểu nào khác. Sau đây là khai báo một mảng của những con trỏ tới một integer :

int *contro[MAX];

Nó khai báo contro như thể một mảng những con trỏ MAX kiểu integer. Vì thế, mỗi thành phần trong contro, giờ đây giữ một con trỏ tới một giá trị int. Ví dụ sau sử dụng 3 số integer, mà sẽ được lưu giữ trong một mảng những con trỏ như sau :

#include 
 
using namespace std;
const int MAX = 3;
 
int main ()
{
   int  var[MAX] = {10, 100, 200};
   int *contro[MAX];
 
   for (int i = 0; i < MAX; i++)
   {
      contro[i] = &var[i]; // gan dia chi cua so nguyen.
   }
   for (int i = 0; i < MAX; i++)
   {
      cout << "Gia tri cua var[" << i << "] = ";
      cout << *contro[i] << endl;
   }
   return 0;
}

Khi code trên được biên dịch và thực thi, nó cho hiệu quả sau :

Gia tri cua var[0] = 10
Gia tri cua var[1] = 100
Gia tri cua var[2] = 200

Bạn hoàn toàn có thể sử dụng một mảng những con trỏ tới ký tự để lưu giữ một list những chuỗi như sau :

#include 
 
using namespace std;
const int MAX = 4;
 
int main ()
{
   char *tensv[MAX] = {
                   "Nguyen Thanh Tung",
                   "Tran Minh Chinh",
                   "Ho Ngoc Ha",
                   "Hoang Minh Hang",
   };

   for (int i = 0; i < MAX; i++)
   {
      cout << "Gia tri cua tensv[" << i << "] = ";
      cout << tensv[i] << endl;
   }
   return 0;
}

Chạy chương trình C + + trên sẽ cho hiệu quả như hình sau :
Mảng Con Trỏ Trong C++

V. Con Trỏ Hàm Trong C + +

Con trỏ hàm là một biến tàng trữ địa chỉ của một hàm, trải qua biến đó, ta hoàn toàn có thể gọi hàm mà nó trỏ tới .
Cú pháp khai báo con trỏ hàm :

(*)();

int(*fcnPtr)(int); // con trỏ hàm nhận vào 1 biến kiểu int và trả về kiểu int
void(*fcnPtr)(int, int); // con trỏ hàm nhận vào 2 biến kiểu int và trả về kiểu void

Chú ý : Dấu ngoặc ( ) quanh * fcnPtr là bắt buộc .

VI. Con Trỏ Trong Class C + +

Một con trỏ tới một lớp trong C + + được triển khai theo cách giống hệt như một con trỏ tới một cấu trúc ; và để truy vấn những thành viên của một con trỏ tới một lớp bạn sử dụng toán tử truy vấn thành viên trong C + + là toán tử ->, như khi bạn thực thi với những con trỏ tới cấu trúc. Cũng như với toàn bộ con trỏ, bạn phải khai báo con trỏ trước khi sử dụng nó .
Bạn thử ví dụ sau để hiểu khái niệm con trỏ tới một lớp trong C + + :

#include 
 
using namespace std;

class Box
{
   public:
      // phan dinh nghia Constructor
      Box(double dai=1.0, double rong=1.0, double cao=1.0)
      {
         cout <<"Constructor duoc goi." << endl;
         chieudai = dai;
         chieurong = rong;
         chieucao = cao;
      }
      double theTich()
      {
         return chieudai * chieurong * chieucao;
      }
   private:
      double chieudai;     // chieu dai cua mot box
      double chieurong;    // chieu rong cua mot box
      double chieucao;     // chieu cao cua mot box
};

int main(void)
{
   Box Box1(2.4, 4.2, 2.2);    // khai bao box1
   Box Box2(4.5, 2.0, 3.2);    // khai bao box2
   Box *controBox;                // khai bao con tro toi mot class.

   // luu giu dia chi cua doi tuong dau tien
   controBox = &Box1

   // bay gio thu truy cap mot thanh vien boi su dung toan tu truy cap thanh vien
   cout << "The tich cua Box1 la: " << controBox->theTich() << endl;

   // luu giu dia chi cua doi tuong thu hai
   controBox = &Box2

   // bay gio thu truy cap mot thanh vien boi su dung toan tu truy cap thanh vien
   cout << "The tich cua Box2 la: " << controBox->theTich() << endl;
  
   return 0;
}

Biên dịch và chạy chương trình C + + trên sẽ cho tác dụng sau :
Con Trỏ Trong Class C++

VII. Con Trỏ Trong Struct C + +

Chào các bạn đang theo dõi khóa học lập trình trực tuyến ngôn ngữ C++.
Chúng ta cùng tiếp tục tìm hiểu về kiểu dữ liệu tự định nghĩa thông qua từ khóa struct mà ngôn ngữ C++ hỗ trợ. Trong bài học này, mình sẽ trình bày về kiểu struct khi sử dụng kết hợp với con trỏ.

Như những bạn đã học trong bài trước, sau khi tất cả chúng ta tự định nghĩa một struct, compiler sẽ coi tên gọi của struct đó như thể một kiểu tài liệu. Điều này có nghĩa khi tất cả chúng ta sử dụng những kiểu tài liệu built-in để tạo ra những biến, tham chiếu hoặc con trỏ thì tất cả chúng ta cũng hoàn toàn có thể sử dụng kiểu struct để tạo ra biến struct, tham chiếu struct và con trỏ kiểu struct ( Pointer to struct ) .
Pointer to struct
Đầu tiên, tất cả chúng ta cùng định nghĩa một kiểu tài liệu theo ý muốn. Dưới đây, mình định nghĩa một kiểu tài liệu có tên là Letter :

struct Letter
{
   
};

Trong struct Letter mình chưa định nghĩa những trường tài liệu, lúc này Letter là một kiểu tài liệu rỗng. Nhưng ngôn từ C + + vẫn đặt kích cỡ của kiểu Letter này là 1 bytes .
Mục đích là để bảo vệ địa chỉ của 2 biến được tạo ra sẽ có địa chỉ khác nhau. Tuy nhiên, định nghĩa ra một struct rỗng không có công dụng gì trong chương trình, tất cả chúng ta cùng thêm vào một số ít trường tài liệu cho Letter :

struct Letter
{
   char from[50];
   char to[50];
};

Một lá thư sẽ có thông tin về người gửi và người nhận, nên mình thêm vào 2 trường tài liệu kiểu C-style string dùng để lưu thông tin mà người dùng điền vào một lá thư .
Mình vừa định nghĩa xong một kiểu tài liệu mới để Giao hàng cho chương trình của mình. Bây giờ tất cả chúng ta cùng tạo ra một đơn vị chức năng từ kiểu tài liệu trên ( mình thao tác luôn trong hàm main ) :

int main()
{
   Letter myLetter;
   
   return 0;
}

Với mỗi biến kiểu Letter được tạo ra, chương trình sẽ nhu yếu cấp phép 100 bytes ( 50 bytes cho trường tài liệu from và 50 bytes cho trường tài liệu to ), và chắc như đinh rồi, biến đó sẽ có một địa chỉ xác lập được trải qua toán tử address-of .

int main()
{
   Letter myLetter;
   std::cout << "Address of myLetter: " << &myLetter << std::endl;
   std::cout << "Address of from field: " << &myLetter.from << std::endl;
   
   return 0;
}

Ở đoạn chương trình trên, mình in ra địa chỉ của biến myLetter, đồng thời in ra luôn địa chỉ của trường tài liệu from của biến myLetter. Kết quả cho thấy 2 địa chỉ được in ra có giá trị trọn vẹn giống nhau. Điều này có nghĩa địa chỉ của trường tài liệu tiên phong trong một biến struct cũng là địa chỉ của biến struct đó .
Các bạn hoàn toàn có thể liên hệ struct với mảng một chiều trong C / C + +, khi mảng một chiều mà tập hợp những thành phần có cùng kiểu tài liệu được phủ bọc bởi tên mảng một chiều và địa chỉ của mảng một chiều cũng là địa chỉ của thành phần tiên phong trong mảng, một biến struct sẽ gồm có tập hợp những trường tài liệu mà địa chỉ của biến struct sẽ là địa chỉ của trường tài liệu được khai báo tiên phong trong struct .
Và như những bạn cũng đã học về con trỏ ( Pointer ), kiểu tài liệu của con trỏ dùng để xác lập kiểu tài liệu của vùng nhớ mà con trỏ hoàn toàn có thể trỏ đến. Vậy thì để cho con trỏ trỏ đến một địa chỉ của biến kiểu struct, tất cả chúng ta cần có một con trỏ cùng kiểu struct với biến được trỏ đến .

Letter myLetter;
Letter *pLetter = &myLetter

Dù size của kiểu tài liệu struct có lớn bao nhiêu, biến con trỏ cũng chỉ có size 4 bytes trên hệ điều hành quản lý 32 bits và size 8 bytes trên hệ quản lý 64 bits ( đủ để trỏ đến hàng loạt địa chỉ trên bộ nhớ ảo ) .
Access struct members
Trong bài học kinh nghiệm trước, những bạn đã biết cách truy vấn đến những trường tài liệu của những biến struct trải qua thành viên selection operator ( dấu chấm ). Nhưng khi sử dụng Pointer to struct, thành viên selection operator được sử dụng dưới cách viết khác. Để phân biệt sự khác nhau khi sử dụng thành viên selection operator cho biến struct thường thì và một Pointer to struct, những bạn cùng xem ví dụ bên dưới :

struct BankAccount
{
   __int64 accountNumber;
   __int64 balance;
};

int main()
{
   BankAccount myAccount = { 123456789, 50 }; // $50
   BankAccount *pAccount = &myAccount 

   std::cout << "My bank account number: " << myAccount.accountNumber << std::endl;
   std::cout << "My bank account number: " << pAccount->accountNumber << std::endl;

   std::cout << "My balance: " << myAccount.balance << std::endl;
   std::cout << "My balance: " << pAccount->balance << std::endl;

   return 0;
}

Như những bạn thấy, tác dụng của việc truy xuất giá trị trải qua tên biến struct và con trỏ kiểu struct là trọn vẹn giống nhau, và chúng đều dùng toán tử thành viên selection. Tuy nhiên, để phân biệt biến con trỏ và biến thường thì, biến con trỏ kiểu struct sẽ truy vấn đến những trường tài liệu trong vùng nhớ bằng toán tử ( -> ). Hai toán tử này cùng tên, chỉ khác nhau về cách trình diễn .

Một số nhầm lần khi sử dụng struct và Pointer to struct

Khi mới khám phá về Pointer to struct, những bạn hoàn toàn có thể bị nhầm lẫn giữa cách khởi tạo hoặc gán giá trị cho biến struct thường thì và biến con trỏ struct .

struct BankAccount
{
   __int64 accountNumber;
   __int64 balance;
};

int main()
{
   BankAccount myAccount = { 12345, 50 };

   BankAccount *pAccount = { 12345, 50 }; //error

   return 0;
}

Đoạn chương trình trên báo lỗi vì biến con trỏ chỉ nhận giá trị là địa chỉ. Tuy nhiên, lỗi này hoàn toàn có thể thấy thuận tiện vì Visual studio đưa ra thông tin lỗi ngay. Dưới đây là cách gán giá trị đúng khi mình sử dụng toán tử dereference cho biến con trỏ struct để biến hóa giá trị bên trong vùng nhớ :

struct BankAccount
{
   __int64 accountNumber;
   __int64 balance;
};

int main()
{
   BankAccount myAccount = { 0, 0 };

   BankAccount *pAccount = &myAccount

   *pAccount = { 12345, 50 };

   std::cout << pAccount->accountNumber << " " << pAccount->balance << std::endl;

   return 0;
}

Hoặc một cách khác là tất cả chúng ta cấp phép vùng nhớ cho biến con trỏ struct, và dereference đến đó để gán giá trị cho nó :

BankAccount *pAccount = new BankAccount;
*pAccount = { 12345, 50 };

Và những bạn chú ý quan tâm khi sử dụng biến kiểu con trỏ struct thì tất cả chúng ta sử dụng toán tử thành viên selection này ( -> ). Có một số ít bạn nhầm lẫn giữa biến con trỏ struct và trường tài liệu kiểu con trỏ. Ví dụ :

struct BankAccount
{
   char *name;
   __int64 accountNumber;
   __int64 balance;
};

Mình thêm vào struct một trường tài liệu kiểu con trỏ char nhưng việc truy xuất đến trường tài liệu này không có gì đổi khác khi mình sử dụng biến struct thường thì .

BankAccount myAccount = { "Le Tran Dat", 12345, 50 };

std::cout << myAccount.name << std::endl;
std::cout << myAccount.accountNumber << std::endl;
std::cout << myAccount.balance << std::endl;

Sẽ phức tạp hơn một chút ít khi những bạn sử dụng những nested struct. Ví dụ :

struct BankAccount
{
   Date registrationDate;
   __int64 accountNumber;
   __int64 balance;
};

int main()
{
   BankAccount *pAccount = new BankAccount;
   *pAccount = { {2, 5, 2016}, 12345, 50 };

   std::cout << pAccount->registrationDate.year << std::endl;

   return 0;
}

Như những bạn thấy, từ biến con trỏ pAccount truy xuất vào những trường tài liệu bên trong thì mình dùng toán tử ( -> ), nhưng trường tài liệu Date trong struct BankAccount là biến thường thì, nên mình dùng dấu chấm để truy xuất tài liệu ngày đăng kí .
Con Trỏ Trong Struct C++

VIII. Con Trỏ Null Trong C + +

Con trỏ NULL trong C + + là một hằng với một giá trị là 0 được định nghĩa trong một vài thư viện chuẩn, gồm iostream .

#include 
 
using namespace std;
 
int main () {
    int  *ptr = NULL;
    cout << "Gia tri cua contro la " << ptr ;
    return 0;
}

Kết quả :

Gia tri cua contro la 0

Trên hầu hết những hệ quản lý, những chương trình không được phép truy vấn bộ nhớ tại địa chỉ 0, vì bộ nhớ đó được dự trữ bởi hệ điều hành quản lý. Tuy nhiên, địa chỉ bộ nhớ 0 có ý nghĩa đặc biệt quan trọng, nó chỉ ra rằng con trỏ không được trỏ tới một vị trí ô nhớ hoàn toàn có thể truy vấn. Nhưng theo qui ước, nếu một con trỏ chứa giá trị 0, nó được xem như thể không trỏ tới bất kể thứ gì .
Để kiểm tra một con trỏ null trong C + +, bạn hoàn toàn có thể sử dụng lệnh if như sau :

if(contro)     // true neu contro khong la NULL
if(!contro)    // true neu contro la NULL

Con Trỏ Null Trong C++

IX. Nhập Xuất Mảng Bằng Con Trỏ Trong C + +

Bằng cách sử dụng con trỏ mảng, tất cả chúng ta hoàn toàn có thể chỉ định vị trí những thành phần trong mảng, cũng như là truy vấn và lấy giá trị của những thành phần đó .
Ứng dụng điều này, tất cả chúng ta cũng hoàn toàn có thể nhập xuất mảng bằng con trỏ trong C + + như sau .

Nhập mảng bằng con trỏ trong C + +

Trong bài Nhập xuất mảng trong C + + tất cả chúng ta đã biết cách tạo hàm nhập trực tiếp những giá trị từ bàn phím vào mảng như sau :

/*Tạo hàm nhập mảng 1 chiều trong C++*/
void input_array(int array[], int length){
    //array: tên mảng
    //length: độ dài mảng
    for (short i = 0; i < length; i++) cin >> array[i];
}

Trong đó array và length lần lượt là tên và độ dài ( số thành phần ) của mảng cần nhập .
Để nhập mảng bằng con trỏ trong C + + tất cả chúng ta chỉ cần sử dụng giá trị con trỏ thay cho mảng, và thay vì dùng index để chỉ định vị trí nhập tài liệu, thì tất cả chúng ta sẽ sử dụng trực tiếp giá trị con trỏ để chỉ định vị trí cần nhập. Chúng ta viết hàm nhập mảng bằng con trỏ trong C + + như sau :

/*Tạo hàm nhập mảng bằng con trỏ trong C++*/
void input_array(int array[], int length){
    //array: tên mảng
    //length: độ dài mảng
    for (short i = 0; i < length; i++) cin >> *(array + i);
}

Lưu ý tại đây tất cả chúng ta sử dụng lệnh cin để nhập tài liệu vào mảng, nên cần chỉ định bản thân tài liệu mà con trỏ chỉ đến bằng cách thêm dấu hoa thị * trước con trỏ .
Tuy nhiên nếu sử dụng hàm scanf được thừa kế từ ngôn từ C để nhập mảng bằng con trỏ trong C + +, thay vì chỉ định tài liệu thì tất cả chúng ta cần chỉ định địa chỉ của tài liệu đã được lưu vào con trỏ như sau :

/*Tạo hàm nhập mảng bằng con trỏ trong C*/
void input_array(int *array, int length){
    //array: tên mảng
    //length: độ dài mảng
    for (short i = 0; i < length; i++) scanf("%d", (array + i));
}

Xuất mảng bằng con trỏ trong C + +

Trong bài xuất xuất mảng trong C + + tất cả chúng ta đã biết cách tạo hàm xuất trực tiếp những giá trị của mảng như sau :

/*Tạo hàm xuất mảng 1 chiều trong C++*/
void show_array(int array[], int length){
    //array: tên mảng
    //length: độ dài mảng
    for(short i = 0; i < length; i++)  cout << array[i] <<' ';   
    cout << endl;
}

Trong đó array và length lần lượt là tên và độ dài ( số thành phần ) của mảng cần xuất .
Để xuất mảng bằng con trỏ trong C + + tất cả chúng ta chỉ cần sử dụng con trỏ thay cho mảng, và thay vì truy xuất giá trị những thành phần của mảng bằng index thì tất cả chúng ta sẽ dùng tên con trỏ và dấu hoa thị để xuất giá trị đó. Chúng ta viết hàm xuất mảng bằng con trỏ trong C + + như sau :

/*Tạo hàm xuất mảng bằng con trỏ trong C++*/
void show_array(int array[], int length){
    //array: tên mảng
    //length: độ dài mảng
    for(short i = 0; i < length; i++)  cout << *(array + i) <<' ';   
    cout << endl;
}

Chương trình mẫu nhập xuất mảng bằng con trỏ trong C + +

Dưới đây là chương trình mẫu sử dụng những hàm trên để nhập xuất mảng bằng con trỏ trong C + + :

#include 
using namespace std;

/*Tạo hàm nhập mảng bằng con trỏ trong C++*/
void input_array(int array[], int length){
    //array: tên mảng
    //length: độ dài mảng
    for (short i = 0; i < length; i++) cin >> *(array + i);
}

/*Tạo hàm xuất mảng bằng con trỏ trong C++*/
void show_array(int array[], int length){
    //array: tên mảng
    //length: độ dài mảng
    for(short i = 0; i < length; i++)  cout << *(array + i) <<' ';   
    cout << endl;
}

int main(){
    /*Nhập mảng bằng con trỏ trong C++*/
    int n;
    cout << ">>Nhap so phan tu: ";
    cin >>  n;
 
    int array[n], *p;
    cout << (">>Nhap phan tu:\n");
    input_array(array, n);
    
    /*Xuất mảng bằng con trỏ trong C++*/ 
    cout << (">>Mang vua nhap:\n"); 
    show_array(array, n);
}

Kết quả:

>>Nhap so phan tu: 5
>>Nhap phan tu:
1 2 3 4 5
>>Mang vua nhap:
1 2 3 4 5

Nhập Xuất Mảng Bằng Con Trỏ Trong C++

X. Con Trỏ Và Tham Chiếu Trong C + +

C và C + + tương hỗ con trỏ cái mà khác với hầu hết những ngôn từ lập trình khác. Các ngôn từ khác gồm có C + +, Java, Python, Ruby, Perl và PHP đều tương hỗ tham chiếu .
Nhìn vẻ bên ngoài, cả hai tham chiếu và con trỏ đều rất giống nhau, cả hai đều được sử dụng để có một biến cung ứng quyền truy vấn cho một biến khác. Với việc cả hai đều cung ứng nhiều năng lực giống nhau, người ta thường không rõ điều gì độc lạ giữa những chính sách khác nhau này. Trong bài viết này, tôi sẽ nỗ lực minh họa sự độc lạ giữa con trỏ và tham chiếu .
Con trỏ : Con trỏ là một biến chứa địa chỉ bộ nhớ của một biến khác. Một con trỏ cần được deference với toán tử * để truy vấn vào vị trí bộ nhớ mà nó trỏ tới .

Tham chiếu: Một biến tham chiếu là một bí danh, tức là một tên khác của một biến đã tồn tại. Một tham chiếu, giống như một con trỏ, cũng được hiện thựcbằng cách lưu trữ địa chỉ của một đối tượng.
Một tham chiếu có thể được coi là một con trỏ hằng (đừng nhầm với một con trỏ đến một giá trị không đổi!) với tính năng tự động chuyển hướng, tức là trình biên dịch sẽ áp dụng toán tử * cho bạn.

int i = 3; 
 
// Một con trỏ đến biến i
// (lưu trữ địa chỉ của i)
int *ptr = &i 
 
// Một tham chiếu (bí danh) của i.
int &ref = i;

Sự khác nhau giữa Con trỏ và Tham chiếu

Khởi tạo

Một con trỏ có thế được khai báo và khởi tạo đồng thời hoặc trên nhiều dòng .

C++
int a = 10;        
int *p = &a    
hay
int *p;
p = &a

Trong khi tham chiếu phải được khởi tạo cùng lúc với khai báo .

int a=10;
int &p=a;  //OK
nhưng
int &p
p=a;      //NOK

Chú ý : Sự độc lạ này hoàn toàn có thể đổi khác từ trình biên dịch này sang trình biên dịch khác. Sự độc lạ trên là so với Turbo IDE .

Gán lại giá trị

Một con trỏ hoàn toàn có thể được gán lại. Thuộc tính này có ích cho việc tiến hành những cấu trúc tài liệu như list link, cây, v.v. Xem ví dụ sau :

int a = 5;
int b = 6;
int *p;
p =  &a
p = &b

Trong khi đó, tham chiếu không gán lại mà phải được gán ngay lúc khởi tạo .

int a = 5;
int b = 6;
int &p = a;
int &p = b;   //Tại dòng này sẽ hiện lỗi là "không được khai báo nhiều lần"
 
//Tuy nhiên, lệnh như dưới đây thì ok.
int &q=p;

Địa chỉ bộ nhớ

Một con trỏ có địa chỉ bộ nhớ và kích cỡ riêng của nó trên ngăn xếp trong khi một tham chiếu san sẻ cùng địa chỉ bộ nhớ ( với biến gốc ) nhưng cũng chiếm 1 số ít khoảng trống trên ngăn xếp .

int &p = a;
cout << &p << endl << &a // Địa chỉ của p và a là như nhau

Giá trị NULL

Con trỏ hoàn toàn có thể được gán NULL trực tiếp, trong khi tham chiếu không hề. Các ràng buộc tương quan đến tham chiếu ( không NULL, không gán lại ) bảo vệ rằng những hoạt động giải trí cơ bản không rơi vào trường hợp ngoại lệ .

Con trỏ đến con trỏ

Bạn hoàn toàn có thể có những con trỏ đến con trỏ phân phối nhiều Lever chuyển hướng bổ trợ. Trong khi đó, những tham chiếu chỉ cung ứng một mức chuyển hướng .

//Con trỏ,
int a = 10;
int *p;
int **q;  //Con trỏ đến con trỏ.
p = &a
q = &p
 
//Đối với tham chiếu,
 
int &p = a;
int &&q = p; //Lỗi, không có tham chiếu của tham chiếu.

Các phép tính toán học

Các phép toán số học khác nhau hoàn toàn có thể được triển khai trên con trỏ trong khi không có thứ gọi là Số học tham chiếu. ( Nhưng bạn hoàn toàn có thể lấy địa chỉ của một đối tượng người dùng được trỏ bởi một tham chiếu và thực thi số học con trỏ trên đó như và obj + 5 )

Khi nào sử dụng cái nào

Hiệu suất trọn vẹn giống nhau, vì những tham chiếu được tiến hành bên trong dưới dạng con trỏ. Tuy nhiên, bạn vẫn hoàn toàn có thể ghi nhớ 1 số ít điểm để quyết định hành động khi nào sử dụng cái gì :

Sử dụng tham chiếu:

  • Trong các tham số hàm và kiểu trả về.

Sử dụng con trỏ:

  • Sử dụng con trỏ nếu cấn tính toán con trỏ số học hoặc NULL. Ví dụ đối với mảng (Lưu ý rằng truy cập mảng được thực hiện bằng cách sử dụng số học con trỏ).
  • Để triển khai các cấu trúc dữ liệu như danh sách liên kết, cây, v.v. và các thuật toán của chúng vì để trỏ ô khác nhau, chúng ta phải sử dụng khái niệm con trỏ.

Con Trỏ Và Tham Chiếu Trong C++

XI. Ý Nghĩa Con Trỏ This Trong C + +

Con trỏ this trong C + +

This là một con trỏ đặc biệt quan trọng dùng để trỏ đến địa chỉ của đối tượng người tiêu dùng hiện tại. Như vậy để truy vấn đến những thuộc tính, phương pháp của đối tượng người dùng hiện tại thì ta sẽ sử dụng con trỏ this. Hãy xem ví dụ dưới đây .
Ví dụ

#include   
using namespace std;  
class NhanVien { 
    int msnv;    
    string ten;
    int tuoi;
    public:  
       void setData(int msnv, string ten, int tuoi) {  
            this->msnv = msnv;    
            this->ten = ten;    
            this->tuoi = tuoi; 
       }    
       void showData() {
            cout << "Ten nhan vien: " << this->ten << endl;
            cout << "Ma so nhan vien: " << this->msnv << endl;
            cout << "Tuoi: " << this->tuoi << endl;
       }    
};

Trong ví dụ này mình đã tạo ra ba thuộc tính để tàng trữ thông tin của một nhân viên cấp dưới đó là : manv, ten, tuoi. Ngoài ra mình có tạo thêm phương pháp setData ( ) dùng để gán tài liệu cho sinh viên, và showData ( ) dùng để hiển thị tài liệu .
Trong phương pháp setData ( ) mình đã sử dụng từ khóa this -> ten_thuoc_tinh để triển khai phép gán tài liệu cho những thuộc tính, còn ở phương pháp showData ( ) mình cũng sử dụng cú pháp tương tự như để hiển thị tài liệu của những thuộc tính. Như vậy tác dụng của từ khóa this chính là một con trỏ và trỏ đến địa chỉ của đối tượng người tiêu dùng hiện tại .
Câu hỏi đặt ra là đối tượng người dùng hiện tại tại là gì ? Để hiểu rõ hơn thì hãy xem đoạn code sử dụng class trên như sau :
Ví dụ

int main() { 
    // Nhan vien 1
    NhanVien n1 =  NhanVien();
    n1.setData(111231, "Nguyen Van A", 24);
    n1.showData();    
     
    // Nhan vien 2
    NhanVien n2 =  NhanVien();
    n2.setData(111232, "Nguyen Van B", 25);
    n2.showData();
    return 0;  
}

Trong ví dụ này mình đã tạo ra hai đối tượng người tiêu dùng sinh viên đó là n1 và n2, và con trỏ this của n1 sẽ trỏ đến chính đối tượng người dùng n1, con trỏ this của n2 sẽ trỏ đến chính đối tượng người dùng n2, đây ta gọi là đối tượng người dùng hiện tại .
Lưu ý : Trong những phương pháp thông thường ( không phải hàm khởi tạo ) nếu bạn sử dụng tên của biến thì sẽ có hai trường hợp xảy ra .

  • Nếu biến đó không tôn tại trong phương thức mà nó lại trùng với tên thuộc tính thì mặc nhiên nó sẽ hiểu đó là thuộc tính.
  • Nếu biến đó có khai báo trong phương thức thì ta sẽ hiểu đó là biến bình thường, không phải là thuộc tính.

Một ví dụ khác về con trỏ this

Bạn hãy xem ví dụ dưới đây, đây là một ví dụ mình viết lại ở phần 1 và có một chút ít biến hóa .
Ví dụ

#include   
using namespace std;  
class NhanVien { 
    int msnv;    
    string ten;
    int tuoi;
    public:  
       NhanVien(int msnv, string ten, int tuoi) {  
            cout << "Trong ham xay dung: " << endl;
            cout << "   msnv: " << msnv << endl;
            cout << "   ten: " << ten << endl;
            cout << "   Tuoi: " << tuoi << endl;
            msnv = msnv;    
            ten = ten;    
            tuoi = tuoi; 
       }    
       void HienThi() {
            cout << "Ham in thong tin cua doi tuong nhan vien: " << endl;
            cout << ten << endl;
            cout << "   Ma so nhan vien: " << msnv << endl;
            cout << "   Tuoi: " << tuoi << endl;
       }    
};  
   
int main() {  
    NhanVien n1 =  NhanVien(111231, "Nguyen Van A", 25);    
    n1.HienThi();    
    return 0;  
}

Ý Nghĩa Con Trỏ This Trong C++

XII. Con Trỏ Void Trong C + +

Để tìm hiều về con trỏ void trong C + +, trước hết bạn cần phải nắm vững những kỹ năng và kiến thức cơ bản về con trỏ void. Đừng lo ngại vì Techacademy đã sẵn sàng chuẩn bị cho bạn trong những bài viết sau đây :

Con trỏ void trong C + + là gì

Trong số những kiểu con trỏ, bạn hoàn toàn có thể xác lập một con trỏ hơi khác thường được gọi là con trỏ void .
Giống như những loại con trỏ khác trong C + + thì con trỏ void cũng được sử dụng để tàng trữ địa chỉ của một tài liệu trong bộ nhớ máy tính .
Tuy nhiên điều đặc biệt quan trọng ở đây là, với kiểu tài liệu mà con trỏ void lưu giữ địa chỉ thì chương trình hoàn toàn có thể truy vấn đến địa chỉ của tài liệu đó, nhưng không xác lập được kiểu của nó. Nói cách khác thì con trỏ void được sử dụng để lưu giữ địa chỉ của những kiểu tài liệu không sống sót kiểu tài liệu .

Khai báo con trỏ void trong C + +

Cách khai báo con trỏ void trong C + + cũng tương tự như như với những loại con trỏ khác, tất cả chúng ta viết kiểu void, rồi dấu hoa thị *, và sau cuối là tên con trỏ void như sau :

void * pdata;

Cách viết này cũng tương tự như như với những kiểu con trỏ int hay char ví dụ điển hình :

char * pCharData;  // Con trỏ kiểu char
int  * pIntData;   // Con trỏ kiểu int

Chúng ta cũng hoàn toàn có thể thực thi những thao tác như gán địa chỉ vào con trỏ, hoặc là in địa chỉ được gán vào con trỏ void tựa như như những loại con trỏ khác trong C + +. Ví dụ :

#include 
using namespace std;

int main()
{
    char data  = 'A'; //Khai báo biến data
    void * pdata = &data // Khai báo con trỏ void và gán địa chỉ của biến data vào con trỏ

    cout << "pointer: "<< pdata;//In địa chỉ mà con trỏ lưu giữ

    return 0;
}
// pointer: 0x7ffe529fddbf

Tuy nhiên, không giống như với những kiểu con trỏ khác thì tất cả chúng ta lại không hề triển khai những thao tác với giá trị của biến mà con trỏ void trỏ đến, và do đó cũng không hề biết được kiểu của tài liệu đó là gì. Ví dụ, tất cả chúng ta không hề đọc được giá trị của biến trải qua con trỏ, vì lỗi sau đây sẽ xảy ra :

#include 
using namespace std;

int main()
{
    char data  = 'A'; //Khai báo biến data
    void * pdata = &data// Khai báo con trỏ void và gán địa chỉ của biến data vào con trỏ

    cout << "data: "<< *pdata;//In giá trị tại địa chỉ mà con trỏ lưu giữ

    return 0;
}

Vậy chẳng phải con trỏ void trong C + + rất là vô dụng hay sao ? Tất nhiên là không phải rồi, vì tất cả chúng ta sẽ cần tới con trỏ void trong những trường hợp như dưới đây :

Sử dụng con trỏ void trong C + +

Con trỏ void trong C + + sẽ được sử dụng trong những trường hợp đặc biệt quan trọng sau đây :

Con trỏ vạn năng giúp lưu giữ tất cả các loại giữ liệu trong C++

Một điều dễ hiểu là do con trỏ void không sống sót kiểu của tài liệu mà nó đang chỉ đến, nên nó có năng lực gật đầu và lưu giữ địa chỉ của toàn bộ những loại giữ liệu khác nhau trong C + +. Đây là điều mà những con trỏ khác trong C + + không làm được. Ví dụ như con trỏ kiểu int thì chỉ gật đầu lưu địa chỉ của tài liệu kiểu int, còn con trỏ kiểu char thì cũng chỉ hoàn toàn có thể gật đầu lưu giữ địa chỉ của kiểu giữ liệu char. Nhưng với con trỏ void, void chấp hết ^ _ .
Ví dụ đơn cử, con trỏ void trong C + + dưới đây hoàn toàn có thể lưu giữ địa chỉ của tổng thể những loại giữ liệu mà không sợ lỗi xảy ra trong chương trình .

#include 
using namespace std;

int main(){
    //Khai báo biến
    char   data1;
    short  data2;
    long   data3;
    double data4;

    // Khai báo con trỏ void
    void * pdata;

    //Gán địa chỉ của các loại dữ liệu với nhiều kiểu vào con trỏ void

    pdata = &data1   // pdata --> data1
    pdata = &data2   // pdata --> data2
    pdata = &data3   // pdata --> data3
    pdata = &data4   // pdata --> data4

    return 0;
}

Con trỏ giúp cố ý ẩn kiểu dữ liệu

Vì con trỏ C + + không được cho phép tất cả chúng ta đọc kiểu tài liệu cũng như truy vấn vào tài liệu tại địa chỉ mà nó lưu giữ, nên con trỏ void có vai trò vô cùng quan trong khi tất cả chúng ta muốn ẩn kiểu tài liệu nào đó trong chương trình .
Đây là một thuật toán vô cùng phức tạp yên cầu lượng kỹ năng và kiến thức khá cao, chỉ dành cho những bạn thực sự pro và muốn khám phá sâu về C + + mà thôi .
Con Trỏ Void Trong C++

XIII. Bài Tập Về Con Trỏ Trong C + +

Trong chủ đề này, tất cả chúng ta cùng làm một số ít bài tập về Con trỏ trong C + + .
Bài tập 1
Sử dụng con trỏ trong C + +, bạn hãy viết một chương trình C + + để nhận tài liệu từ người dùng và tìm giá trị lớn nhất của một tập dữ liệu nội bộ .
Lời giải
Dưới đây là chương trình C + + để giải bài tập trên. Mình sử dụng một hàm mà nhận mảng những giá trị tài liệu và kích cỡ của nó. Hàm này trả về con trỏ mà trỏ tới giá trị lớn nhất .

#include 
#include 
using namespace std;
int *findMax(int arr[],int n); 
int main(){    
   int n,i,*p;     
  cout<<"Nhap so du lieu: ";     
  cin>>n;     
  int arr[n];         
  for(i=0;i>arr[i];             
}           
  p=findMax(arr,n);     
  cout<<"Gia tri lon nhat la: "<<*p;     
  getch();     
  return 0; 
}  
 
int *findMax(int data[],int n){     
  int *max=data;     
  int i;    
 for(i=1;i
Chạy chương trình C + + trên sẽ cho hiệu quả như hình sau :
Bài Tập Về Con Trỏ Trong C++
Bài tập 2
Viết một chương trình C + + để nhận 5 giá trị nguyên từ bàn phím. 5 giá trị này sẽ được tàng trữ trong một mảng bởi sử dụng một con trỏ. Sau đó, in những thành phần của mảng trên màn hình hiển thị .
Lời giải
Dưới đây là chương trình C + + để giải bài tập trên .
#include 
#include
using namespace std;

   int main() 
    { 
     int arr[5],i; 
     int *p=arr; 
     cout<<"Nhap 5 so:"; 
     cin>>*p>>*(p+1)>>*(p+2)>>*(p+3)>>*(p+4); 
     cout<<"Cac so ban vua nhap la:\n"; 
     for(i=0;i<5;i++) 
        cout<
Chạy chương trình C + + trên sẽ cho hiệu quả như hình sau :
Bài Tập Về Con Trỏ Trong C++
Sửa đổi giải thuật trên để in những thành phần của mảng theo thứ tự đảo ngược bởi sử dụng một con trỏ .
#include 
#include
using namespace std;

   int main() 
    { 
     int arr[5],i; 
     int *p=arr; 
     cout<<"Nhap 5 so:"; 
     cin>>*p>>*(p+1)>>*(p+2)>>*(p+3)>>*(p+4); 
     cout<<"Cac so ban vua nhap theo thu tu dao nguoc la:\n"; 
     for(i=4;i>=0;i--) 
        cout<<*(p+i)<
Chạy chương trình C + + trên sẽ cho tác dụng như hình sau :
Bài Tập Về Con Trỏ Trong C++

XIV. Ép Kiểu Con Trỏ Trong C + +

Ép kiểu trong C + + là việc gán giá trị của một biến có kiểu tài liệu này tới biến khác có kiểu tài liệu khác . Cú pháp :
(type) value;

Ví dụ :

float c = 35.8f;
int b = (int)c + 1;

Trong ví dụ trên, tiên phong giá trị dấu phảy động c được đổi thành giá trị nguyên 35. Sau đó nó được cộng với 1 và tác dụng là giá trị 36 được lưu vào b .

Phân loại ép kiểu trong C + +

Trong C + +, có hai loại ép kiểu tài liệu :

  1. Nới rộng (widening): Là quá trình làm tròn số từ kiểu dữ liệu có kích thước nhỏ hơn sang kiểu có kích thước lớn hơn. Kiểu biến đổi này không làm mất thông tin.
  2. Thu hẹp (narrowwing): Là quá trình làm tròn số từ kiểu dữ liệu có kích thước lớn hơn sang kiểu có kích thước nhỏ hơn. Kiểu biến đổi này có thể làm mất thông tin

1. Nới rộng (widening)

Ép Kiểu Con Trỏ Trong C++

Nới rộng (widening): Là quá trình làm tròn số từ kiểu dữ liệu có kích thước nhỏ hơn sang kiểu có kích thước lớn hơn. Kiểu biến đổi này không làm mất thông tin. Ví dụ chuyển từ int sang float. Chuyển kiểu loại này có thế được thực hiện ngầm định bởi trình biên dịch.

Ví dụ :

#include 
 
using namespace std;
  
int main() {
    int i = 100;
    long l = i;    // khong yeu cau chi dinh ep kieu
    float f = l;   // khong yeu cau chi dinh ep kieu
    cout << "Gia tri Int: " << i << endl;
    cout << "Gia tri Long: " << l << endl;
    cout << "Gia tri Float: " << f << endl;
    return 0;
}

Kết quả :

Giá trị Int: 100
Giá trị Long: 100
Giá trị Float:  100

2.Thu hẹp (narrowwing)

Ép Kiểu Con Trỏ Trong C++

Thu hẹp (narrowwing): Là quá trình làm tròn số từ kiểu dữ liệu có kích thước lớn hơn sang kiểu có kích thước nhỏ hơn. Kiểu biến đổi này có thể làm mất thông tin như ví dụ ở trên. Chuyển kiểu loại này không thể thực hiện ngầm định bởi trình biên dịch, người dùng phải thực hiện chuyển kiểu tường minh.

Ví dụ :

#include 
 
using namespace std;
  
int main() {
    double d = 100.04;
    long l = (long) d; // yeu cau chi dinh kieu du lieu (long)
    int i = (int) l; // yeu cau chi dinh kieu du lieu (int)
    cout << "Gia tri Double: " << d << endl;
    cout << "Gia tri Long: " << l << endl;
    cout << "Gia tri Int: " << i << endl;
    return 0;
}

Kết quả :

Giá trị Double: 100.04
Giá trị Long: 100
Giá trị Int:  100