Cấp phát bộ nhớ động trong C++

Cap Phat Bo Nho Dong Trong C



Thông thường, khi sử dụng mã nguồn trong ngôn ngữ lập trình C++, trình biên dịch sẽ phân bổ bộ nhớ theo cách thủ công cho biến để lưu trữ dữ liệu. Nó được gọi là cấp phát bộ nhớ tĩnh. Đây là vùng nhớ cố định không thể thay đổi một khi đã khai báo. Đối với kiểu cấp phát bộ nhớ này, hệ điều hành sử dụng ngăn xếp để lưu trữ dữ liệu. Trong cấp phát tĩnh, bộ nhớ được cấp phát trước khi mã nguồn bắt đầu thực thi.

Trong khi đó, trong cấp phát bộ nhớ động, bộ nhớ được cấp phát trong khi quá trình thực thi đã bắt đầu. Bộ nhớ này được lập trình viên cấp phát thủ công trong thời gian chạy, còn được gọi là cấp phát bộ nhớ thời gian chạy trong C++. Kích thước của bộ nhớ động có thể thay đổi ở bất kỳ vị trí nào trong chương trình vì khi khai báo ta không đề cập đến một kích thước có thể cố định. Chúng tôi chỉ cung cấp giá trị trực tiếp cho biến.

Sự khác biệt của cấp phát bộ nhớ cho các biến bình thường

Trong các biến thông thường, bộ nhớ được cấp phát bởi trình biên dịch sẽ được cấp phát và hủy cấp phát tự động. Khi bộ nhớ được cấp phát động bởi lập trình viên, sau đó anh ta phải loại bỏ hoặc giải phóng bộ nhớ khi nó không được sử dụng trong quá trình thực thi mã nguồn tiếp theo. Tình trạng này gây ra 'rò rỉ bộ nhớ' khi chương trình bị chấm dứt trong khi bộ nhớ chưa được giải phóng.







Toán tử để phân bổ động

Trong C ++, hai toán tử trợ giúp cấp phát và hủy cấp phát bộ nhớ: 'mới' và 'xóa' được sử dụng để cấp phát và hủy cấp phát bộ nhớ theo cách tốt hơn.



nhà điều hành mới

Nó biểu thị nhu cầu cấp phát bộ nhớ. Toán tử mới khởi tạo bộ nhớ và trả về địa chỉ của bộ nhớ được cấp phát đó cho biến con trỏ nếu có đủ bộ nhớ.



đối tượng con trỏ = Mới dữ liệu - loại hình ;

Xóa toán tử

Cũng giống như toán tử mới, toán tử xóa được sử dụng để xóa bộ nhớ đã cấp phát. Trong C++, lập trình viên có thể sử dụng toán tử này để phân bổ.





# Xóa con trỏ_biến;

ví dụ 1

Trong ví dụ này, chúng tôi sẽ giới thiệu hai con trỏ: một là con trỏ kiểu số nguyên và con trỏ kia là con trỏ float. Con trỏ được khởi tạo bằng cách sử dụng dấu hoa thị với chúng.

# Int * điểmInt;
# Nổi *pointfloat;

Bằng cách sử dụng hai máy in này, chúng tôi sẽ phân bổ bộ nhớ một cách linh hoạt.



Vai trò của con trỏ trong cấp phát động:
Bộ nhớ của không gian lưu trữ được phát triển dưới dạng các khối. Bất cứ khi nào chúng ta thực hiện một chương trình hoặc thực hiện bất kỳ thao tác nào, bộ nhớ sẽ được phân bổ cho mục đích cụ thể đó. Bộ nhớ đó có một địa chỉ đặc biệt được liên kết với chương trình xác định quy trình hoặc chương trình nào được phép vào bộ nhớ đó. Bất kỳ khe cắm bộ nhớ nào cũng được truy cập thông qua địa chỉ mà nó thuộc về. Vì vậy, địa chỉ này được lưu trữ thông qua các con trỏ. Nói tóm lại, chúng ta cần con trỏ để truy cập bộ nhớ và theo cách tương tự, để phân bổ một phần bộ nhớ cụ thể cho bất kỳ tác vụ nào. Con trỏ là cần thiết để lưu trữ địa chỉ.

Vì từ khóa 'mới' được sử dụng để cấp phát bộ nhớ động trong cấp phát thủ công, bộ nhớ được cấp phát bởi trình biên dịch. Chúng ta không cần cấp phát bộ nhớ trong thời gian chạy. Nhưng vì phân bổ động là ngẫu nhiên, chúng ta cần xác định các con trỏ và đối với quá trình liên kết, toán tử mới này được sử dụng.

# Pointint = int mới;

Tương tự, con trỏ động cũng bị ràng buộc. Sau quá trình ràng buộc, chúng tôi sẽ gán bất kỳ giá trị nào cho bộ nhớ mà chúng tôi muốn đặt trước cho bất kỳ thao tác nào. Bằng cách khai báo con trỏ, chúng ta gán một giá trị cụ thể cho bộ nhớ.

# *điểmInt = 50;

Một giá trị float cho các float điểm cũng được khai báo. Hiển thị các giá trị sau khi gán.

Như chúng ta đã thảo luận, toán tử 'mới' được sử dụng để phân bổ trong khi 'xóa' được sử dụng để phân bổ bộ nhớ. Vì vậy, khi bạn đã hoàn thành tác vụ hoặc thao tác trong mã, chúng tôi sẽ xóa bộ nhớ mà chúng tôi đã phân bổ cho tác vụ.

Tốt hơn là giải phóng phần bộ nhớ đó để bất kỳ quy trình nào khác có thể tận dụng điều này. Chúng tôi sẽ áp dụng phân bổ này cho cả hai con trỏ.

Xóa điểm trôi nổi ;

Sau khi bạn lưu mã trên trình soạn thảo văn bản, thiết bị đầu cuối Ubuntu cho phép bạn thực thi mã nguồn bên trong tệp thông qua trình biên dịch g++.

$ g++ -o mem mem.c
$./mem

Khi thực hiện, bạn sẽ thấy các giá trị được gán cho bộ nhớ.

ví dụ 2

Ví dụ này có sự tham gia của tương tác người dùng. Chúng tôi sẽ lấy một biến số sẽ chứa một giá trị từ người dùng. Chương trình này sẽ lưu trữ kết quả trong GPA của sinh viên. Tất cả các kết quả sẽ được lưu trong thời gian chạy.

Khi người dùng nhập số lượng học sinh, bộ nhớ sẽ được phân bổ theo từng số. Một con trỏ kiểu float được khởi tạo ở đây sẽ được sử dụng trong cấp phát bộ nhớ cho các kết quả.

Chúng tôi lấy con trỏ ở dạng float vì GPA ở dạng ký hiệu thập phân. Chúng tôi lấy một mảng kiểu con trỏ cho điểm trung bình vì nó có thể dẫn đến một số học sinh.

ptr = Mới trôi nổi [ trên một ]

Mảng con trỏ này với từ khóa 'mới' sẽ liên kết việc thực thi với bộ nhớ. Điểm trung bình sẽ được nhập cho mỗi học sinh. Vì chúng tôi không quen thuộc với số lượng sinh viên mà người dùng muốn thêm, chúng tôi đã sử dụng vòng lặp for để nhập điểm trung bình cho đến số đã nhập. Trong mỗi lần lặp lại vòng lặp, người dùng được yêu cầu nhập kết quả xác định học sinh. Khi kết quả được lưu, chúng tôi sẽ lại sử dụng một vòng lặp để hiển thị tất cả điểm trung bình của học sinh. Cuối cùng, mảng kiểu con trỏ bị xóa vì mục đích lưu trữ động đã hoàn thành.

Xóa bỏ [ ] ptr ;

Bây giờ chúng ta sẽ thực thi đoạn mã trên. Đầu tiên, người dùng sẽ được yêu cầu nhập số lượng học sinh. Sau đó, điểm trung bình cho mỗi sinh viên sẽ được nhập vào.

ví dụ 3

Ví dụ này sử dụng các toán tử mới và xóa cho đối tượng của lớp. Lớp này chứa một biến riêng kiểu số nguyên lưu trữ tuổi. Trong phần công khai của một lớp, hàm tạo được tạo sẽ khởi tạo tuổi thành số '10'. Một chức năng khác được sử dụng ở đây sẽ hiển thị tuổi được khởi tạo trong hàm tạo.

Bây giờ chúng ta sẽ đi tới chương trình chính để phân bổ động. Đối tượng của lớp được tạo động.

Sinh viên * ptr = Mới sinh viên ( ) ;

Khi đối tượng được hình thành, hàm tạo sẽ được triển khai tự động. Một lời gọi hàm sẽ được thực hiện để lấy tuổi. Điều này sẽ được thực hiện thông qua ptr.

Ptr - > lấy tuổi ( ) ;

Và cuối cùng, bộ nhớ sẽ được giải phóng.

Sự kết luận

Cấp phát bộ nhớ động được lập trình viên cấp phát tại thời điểm chạy thay vì bộ nhớ cố định được xác định bởi trình biên dịch. Việc phân bổ này dựa trên cơ sở ngẫu nhiên và có thể bị loại bỏ sau khi sử dụng. Trong khi đó, trong hầu hết các trường hợp, trước khi loại bỏ, quá trình thực hiện dừng lại và phân bổ động này sau đó gây ra rò rỉ bộ nhớ. Chúng tôi đã triển khai hiện tượng này theo các cách tiếp cận khác nhau trong hệ thống Ubuntu Linux bằng ngôn ngữ lập trình C++.