Các dạng bài tập với con trỏ và lời giải năm 2024

Con trỏ trong lập trình là 1 định nghĩa hơi khó nhằn đối với các 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 có thể hiểu và thao tác với dữ liệu trong bộ nhớ máy tính, và những kiến ​​thức liên quan mà bạn học được thông qua con trỏ cũng rất hữu ích cho việc học các ngôn ngữ hướng đối tượng sau này như Java chẳng hạn.

Hãy cùng tìm hiểu 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 này nhé.

Danh Mục Bài Viết

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ụ, chúng ta khai báo con trỏ tên p với kiểu int như sau:

int *p; Lưu ý là các cách viết sau đây cũng được chấp nhận khi khai báo con trỏ trong C++:

int* p; int * p;

Khai Báo Con Trỏ Trong C++

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

Ngôn ngữ C++ hỗ trợ ba loại cấp phát bộ nhớ cơ bản, hai loại trong số đó bạn đã được học ở các bài học 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 tất cả những trường hợp, cấp phát bộ nhớ tĩnh và tự động có thể đáp ứng tốt các đề nghị 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 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 chúng ta cần lưu trữ danh sách nhân viên trong một công ty, nhưng chúng ta không biết trước được công ty đó sẽ có bao nhiêu nhân viên.

Đối với cấp phát bộ nhớ tĩnh và tự động, 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. Vì vậy, điều tốt nhất chúng ta có thể làm là cố gắng đoán một kích thước tối đa của các 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 lãng phí bộ nhớ nếu các biến không thực sự sử dụng hết kích thước khi khai báo. Ví dụ: nếu công ty chỉ có 100 nhân viên, chúng ta có 400 vùng nhớ nhân viên không được sử dụng tới.

+ Thứ hai, hầu hết các biến thông thường [bao gồm mảng tĩnh] được cấp phát 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 1Mb với Visual Studio], nếu yêu cầu cấp phát vùng nhớ vượt quá con số này, chương trình sẽ bị đóng bởi hệ điều hành 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, trong khi mảng staff chỉ có 500 phần tử. Lúc này, chương trình sẽ bị giới hạn bởi kích thước được khai báo ban đầu.

Để giải quyết những hạn chế trên, cấp phát bộ nhớ động được ra đời.

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 dữ liệu trong bộ nhớ máy tính, và bằng cách truy cập vào địa chỉ này, chúng ta có thể lấy được giá trị của dữ liệu tại đó.

Ngoài ra thì giá trị của con trỏ cũng là một số, nên chúng ta cũng có thể thực hiện các 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ị.

Do đó, con trỏ trong C sẽ được dùng để làm 1 trong 2 công việc 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 chúng ta hiểu về khái niệm mảng các con trỏ, 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  lỗi stack overflow   
4
Ý 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 các kiến thức cơ bản về con trỏ void. Đừng lo lắng vì Techacademy đã chuẩn bị cho bạn trong các bài viết sau đây:

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

Trong số các kiểu con trỏ, bạn có thể xác định một con trỏ hơi khác thường được gọi là con trỏ void.

Giống như các loại con trỏ khác trong C++ thì con trỏ void cũng được sử dụng để lưu trữ địa chỉ của một dữ liệu trong bộ nhớ máy tính.

Tuy nhiên điều đặc biệt ở đây là, với kiểu dữ liệu mà con trỏ void lưu giữ địa chỉ thì chương trình có thể truy cập đến địa chỉ của dữ liệu đó, nhưng không xác định đượ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 các kiểu dữ liệu không tồn tại kiểu dữ 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ư với các loại con trỏ khác, chúng ta viết kiểu void, rồi dấu hoa thị *, và cuối cùng là tên con trỏ void như sau:

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

Cách viết này cũng tương tự như với các kiểu con trỏ int hay char chẳng hạn:

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

Chúng ta cũng có thể thực hiện các 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ương tự như các loại con trỏ khác trong C++. Ví dụ:

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

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

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

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ì chúng ta sẽ cần tới con trỏ void trong các 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 các trường hợp đặc biệt 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 tồn tại kiểu của dữ liệu mà nó đang chỉ đến, nên nó có khả năng chấp nhận và lưu giữ địa chỉ của tất cả các loại giữ liệu khác nhau trong C++. Đây là điều mà các con trỏ khác trong C++ không làm được. Ví dụ như con trỏ kiểu int thì chỉ chấp nhận lưu địa chỉ của dữ liệu kiểu int, còn con trỏ kiểu char thì cũng chỉ có thể chấp nhận 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ụ cụ thể, con trỏ void trong C++ dưới đây có thể lưu giữ địa chỉ của tất cả các loại giữ liệu mà không sợ lỗi xảy ra trong chương trình.

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

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

Vì con trỏ C++ không cho phép chúng ta đọc kiểu dữ liệu cũng như truy cập vào dữ 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 chúng ta muốn ẩn kiểu dữ liệu nào đó trong chương trình.

Đây là một thuật toán vô cùng phức tạp đòi hỏi lượng kiến thức khá cao, chỉ dành cho các bạn thực sự pro và muốn tìm hiểu 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, chúng ta cùng làm một số 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 dữ 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 các giá trị dữ 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

using namespace std; const int MAX = 3; int main [] { int var[MAX] = {10, 100, 200}; for [int i = 0; i < MAX; i++] {

  cout 

Chủ Đề