Ngoài việc cấp phát động các giá trị đơn lẻ, chúng ta cũng có thể cấp phát động các biến mảng. Không giống như một mảng cố định, trong đó kích thước mảng phải được cố định tại thời điểm biên dịch, cấp phát động một mảng cho phép chúng ta chọn độ dài mảng trong thời gian chạy. Để cấp phát động một mảng, chúng ta sử dụng từ khoá new và delete (thường được gọi là new [] và delete []):
/*
Cafedev.vn - Kênh thông tin IT hàng đầu Việt Nam
@author cafedevn
Contact: cafedevn@gmail.com
Fanpage: https://www.facebook.com/cafedevn
Group: https://www.facebook.com/groups/cafedev.vn/
Instagram: https://instagram.com/cafedevn
Twitter: https://twitter.com/CafedeVn
Linkedin: https://www.linkedin.com/in/cafe-dev-407054199/
Pinterest: https://www.pinterest.com/cafedevvn/
YouTube: https://www.youtube.com/channel/UCE7zpY_SlHGEgo67pHxqIoA/
*/
#include <iostream>
#include <cstddef> // std::size_t
int main()
{
std::cout << "Enter a positive integer: ";
std::size_t length{};
std::cin >> length;
int *array{ new int[length]{} }; // use array new. Note that length does not need to be constant!
std::cout << "I just allocated an array of integers of length " << length << '\n';
array[0] = 5; // set element 0 to value 5
delete[] array; // use array delete to deallocate array
// we don't need to set array to nullptr/0 here because it's going to go out of scope immediately after this anyway
return 0;
}
Bởi vì chúng ta đang cấp phát một mảng, C ++ biết rằng không nên sử dụng new và delete không xác định thay vì phiên bản new[], delete[]
Độ dài của mảng được cấp phát động phải là kiểu dữ liệu có thể chuyển đổi thành std :: size_t. Chúng ta có thể sử dụng int, nhưng điều đó sẽ gây ra cảnh báo trình biên dịch khi trình biên dịch được cấu hình với mức cảnh báo cao. Chúng ta có sự lựa chọn giữa việc sử dụng std :: size_t làm độ dài hoặc khai báo độ dài dưới dạng int và sau đó ép kiểu khi chúng ta tạo mảng như sau:
int length{};
std::cin >> length;
int *array{ new int[static_cast<std::size_t>(length)]{} };
Lưu ý rằng vì bộ nhớ này được cấp phát từ một nơi khác với bộ nhớ được sử dụng cho các mảng cố định, kích thước của mảng có thể khá lớn. Bạn có thể chạy chương trình trên và cấp phát một mảng có độ dài 1.000.000 (hoặc thậm chí là 100.000.000) mà không gặp vấn đề gì. Thử nó! Do đó, các chương trình cần phân bổ nhiều bộ nhớ trong C ++ thường làm động như vậy.
Nội dung chính
1. Tự động xóa mảng
Khi xóa một mảng được cấp phát động, chúng ta phải sử dụng delete mảng, đó là delete [].
Điều này cho CPU biết rằng nó cần xóa nhiều biến thay vì một biến duy nhất. Một trong những sai lầm phổ biến nhất mà các lập trình viên mới mắc phải khi xử lý cấp phát bộ nhớ động là sử dụng delete thay vì delete[] khi xóa một mảng được cấp phát động. Sử dụng phiên bản vô hướng của delete trên một mảng sẽ dẫn đến hành vi lỗi không xác định, chẳng hạn như hỏng dữ liệu, rò rỉ bộ nhớ, sự cố hoặc các sự cố khác.
Một câu hỏi thường được hỏi khi xóa array[] là, “Làm cách nào để xóa mảng biết cần xóa bao nhiêu bộ nhớ?” Câu trả lời là mảng new [] theo dõi lượng bộ nhớ đã được cấp cho một biến, do đó, delete [] có thể xóa số lượng thích hợp. Rất tiếc, lập trình viên không thể truy cập kích thước / chiều dài này.
2. Mảng động gần giống như mảng cố định
Trong bài học – Con trỏ và mảng, bạn đã biết rằng một mảng cố định giữ địa chỉ bộ nhớ của phần tử mảng đầu tiên. Bạn cũng đã biết rằng một mảng cố định có thể phân rã thành một con trỏ trỏ đến phần tử đầu tiên của mảng. Ở dạng phân rã này, độ dài của mảng cố định không có sẵn (và do đó kích thước của mảng thông qua sizeof ()) cũng vậy, nhưng nếu không thì có rất ít sự khác biệt.
Mảng động bắt đầu cuộc sống của nó như một con trỏ trỏ đến phần tử đầu tiên của mảng. Do đó, nó có những hạn chế giống nhau ở chỗ nó không biết chiều dài hoặc kích thước của nó. Một mảng động hoạt động giống hệt với một mảng cố định đã phân rã, ngoại trừ người lập trình chịu trách nhiệm định vị lại mảng động thông qua từ khóa delete [].
3. Khởi tạo mảng được cấp phát động
Nếu bạn muốn khởi tạo một mảng được cấp phát động thành 0, thì cú pháp khá đơn giản:
int *array{ new int[length]{} };
Trước C ++ 11, không có cách nào dễ dàng để khởi tạo một mảng động thành giá trị khác 0 (danh sách bộ khởi tạo chỉ hoạt động cho các mảng cố định). Điều này có nghĩa là bạn phải lặp qua mảng và gán giá trị phần tử một cách rõ ràng.
int *array = new int[5];
array[0] = 9;
array[1] = 7;
array[2] = 5;
array[3] = 3;
array[4] = 1;
Siêu khó chịu!
Tuy nhiên, bắt đầu với C ++ 11, giờ đây có thể khởi tạo mảng động bằng cách sử dụng trình khởi tạo danh sách!
int fixedArray[5] = { 9, 7, 5, 3, 1 }; // initialize a fixed array before C++11
int *array{ new int[5]{ 9, 7, 5, 3, 1 } }; // initialize a dynamic array since C++11
// To prevent writing the type twice, we can use auto. This is often done for types with long names.
auto *array{ new int[5]{ 9, 7, 5, 3, 1 } };
Lưu ý rằng cú pháp này không có toán tử = giữa độ dài mảng và danh sách bộ khởi tạo.
Để nhất quán, các mảng cố định cũng có thể được khởi tạo bằng cách sử dụng khởi tạo thống nhất:
int fixedArray[]{ 9, 7, 5, 3, 1 }; // initialize a fixed array in C++11
char fixedArray[]{ "Hello, world!" }; // initialize a fixed array in C++11
Nói rõ kích thước của mảng là tùy chọn. Làm như vậy có thể giúp bắt lỗi sớm, vì trình biên dịch sẽ cảnh báo bạn khi độ dài được chỉ định nhỏ hơn độ dài thực.
Tính đến thời điểm viết bài, GCC vẫn có một lỗi trong đó việc khởi tạo một mảng ký tự được phân bổ động bằng cách sử dụng một chuỗi kiểu C gây ra lỗi trình biên dịch:
char *array = new char[14] { "Hello, world!" }; // doesn't work in GCC, though it should
Nếu bạn cần thực hiện việc này trên GCC, hãy cấp phát động một chuỗi std :: thay thế (hoặc cấp phát mảng char của bạn và sau đó sao chép chuỗi vào).
4. Thay đổi kích thước mảng
Cấp phát động một mảng cho phép bạn thiết lập độ dài mảng tại thời điểm cấp phát. Tuy nhiên, C ++ không cung cấp một cách tích hợp để thay đổi kích thước một mảng đã được cấp phát. Có thể khắc phục hạn chế này bằng cách cấp phát động một mảng mới, sao chép các phần tử và xóa mảng cũ. Tuy nhiên, điều này dễ xảy ra lỗi, đặc biệt khi kiểu của phần tử là một lớp (có các quy tắc đặc biệt điều chỉnh cách chúng được tạo ra).
Do đó, chúng tôi khuyên bạn nên tránh tự mình làm điều này.
May mắn thay, nếu bạn cần khả năng này, C ++ cung cấp một mảng có thể thay đổi kích thước như một phần của thư viện chuẩn được gọi là std :: vector. cafedev sẽ sớm giới thiệu std :: vector.
Cài ứng dụng cafedev để dễ dàng cập nhật tin và học lập trình mọi lúc mọi nơi tại đây.
Nguồn và Tài liệu tiếng anh tham khảo:
Tài liệu từ cafedev:
- Full series tự học C++ từ cơ bản tới nâng cao tại đây nha.
- Ebook về C++ tại đây.
- Các series tự học lập trình MIỄN PHÍ khác
- Nơi liên hệ hợp tác hoặc quảng cáo cùng Cafedevn tại đây.
Nếu bạn thấy hay và hữu ích, bạn có thể tham gia các kênh sau của cafedev để nhận được nhiều hơn nữa:
Chào thân ái và quyết thắng!