Изменение размера массива C++
Хотелось бы получить ответ на вопрос, связанный с переопределением размера массива и дополнением его числами. Интересует следующее: У меня есть массив, определенного размера и заполненный числами. Каким образом мне сделать так, чтобы я мог переопределить размер данного массива и дополнить его другими значениями,старые значения должны остаться.
Думаю в этом направлении-создавать временный массив, а потом из него докидывать в глобальный. Написал вот простенький код.
#include <iostream>
void resize(int size, int *arr)
{
size_t newSize = size;
int* newArr = new int[newSize];
memcpy(newArr, arr, size * sizeof(int));
size = newSize;
delete[] arr;
arr = newArr;
}
int main()
{
int size = 10;
int* arr = new int[size];
//Запись координат
for (int i = 0; i < 10; i++)
{
arr[i] = rand() % 21;
}
resize(size, arr);
}
К примеру Массив 1={1,2,3,4,5},размер массива = 5 потом мне нужно дополнить массив числами 6,7,8,9,10 и чтобы размер был уже равен 10. Заранее благодарю за помощь.
Ответы (3 шт):
Станартный std::vector использует 2 механизма:
Коэффициент приращения (например:
capacity *= 2;)Резервирование (
std::vector::reserve(std::size_t))
void MyVector::push_back(int element) {
if (size_ == capacity_) reserve(capacity_ * 2);
data_[size_++] = element;
}
void MyVector::reserve(std::size_t capacity) {
if (capacity <= capacity_) return;
auto data = new int[capacity];
std::memcpy(data,data_,capacity_*sizeof(int));
delete[] data_;
data_ = data;
capacity_ = capacity;
}
Теоретически std::realloc должен быть эффективнее. Он может просто расширить существующий блок памяти.
void MyVector::reserve(std::size_t capacity) {
if (capacity <= capacity_) return;
auto data = (int*)std::realloc(data_,capacity*sizeof(int));
if (!data) throw std::bad_alloc{};
data_ = data;
capacity_ = capacity;
}
Как было отмечено в комментариях, сишные функции аллокации памяти не могут вызывать конструктор, поэтому данная реализация применима только для примитивных типов не имеющих конструкторов. Однако, в более продвинутой реализации можно использовать "ручное управление памятью" с помощью placement new (статья на Habr), совмещая выделение памяти средствами ОС с помощью std::realloc с созданием объектов с помощью placement new.
В связи со множественными случаями недопонимания произошедшими в комментариях к этому ответу, вынужден отдельно отметить, что способы аллокации и деаллокации памяти и сишными и плюсовыми методами несовместимы и являются UB.
Можно сделать следующим образом:
Используем функцию memset для установки всех элементов arr_new в значение 0. sizeof(int) * newSize определяет количество байт, которые должны быть установлены в 0.
С помощью функции copy копируем элементы из исходного массива arr в новый массив arr_new. min(oldSize, newSize) используем для определения количества элементов, которые будут скопированы. Если новый размер newSize меньше старого размера oldSize, то копируем только первые newSize элементов.
int* Resize(int* arr, int oldSize, int newSize)
{
int* arr_new = new int[newSize];
memset(arr_new, 0, sizeof(int) * newSize);
copy(arr, arr + min(oldSize, newSize), arr_new);
delete[] arr;
return arr_new;
}
Ответ уже был дан, но я хотел бы его подтвердить цифрами.
Копировать можно через memcpy или через copy (тест далее показывает, что они идентичны).
Массив можно расширять на нужный размер, а можно на больший (и вот здесь тест показывает прирост производительности, если не делаем лишние расширения).
Результат теста в релизной сборке:
memcpy alg: 1.393 sec, copy alg: 1.409 sec, capacity alg: 0.042 sec
Код теста (с проверкой идентичности полученных в конце массивов):
#include <iostream>
#include <ctime>
using namespace std;
int* resizeMemCpy(int* arr, size_t oldSize, size_t newSize) {
int* newArr = new int[newSize];
memset(newArr, 0, sizeof(int) * newSize);
memcpy(newArr, arr, min(oldSize, newSize) * sizeof(int));
delete[] arr;
return newArr;
}
int* resizeCopy(int* arr, size_t oldSize, size_t newSize) {
int* arr_new = new int[newSize];
memset(arr_new, 0, sizeof(int) * newSize);
copy(arr, arr + min(oldSize, newSize), arr_new);
delete[] arr;
return arr_new;
}
int* resizeCapacity(int* arr, size_t oldSize, size_t newSize, size_t* capacity) {
if (*capacity >= newSize) {
return arr;
}
size_t oldCapacity = *capacity;
*capacity *= 2;
auto data = new int[*capacity];
memset(data, 0, sizeof(int) * *capacity);
memcpy(data, arr, oldCapacity * sizeof(int));
delete[] arr;
return data;
}
void checkEqual(int* arr1, int* arr2, int* arr3, size_t size) {
for (size_t i = 0; i < size; i++) {
if (arr1[i] != arr2[i]) {
throw exception("content of arr2 not equal arr1");
}
if (arr1[i] != arr3[i]) {
throw exception("content of arr3 not equal arr1");
}
}
}
int main() {
try {
const size_t initSize = 10;
const size_t addSize = 100;
const int N = 1000;
const int repeat = 100;
double clocksMemCpy = 0;
double clocksCopy = 0;
double clocksCapacity = 0;
clock_t start, end;
for (int i = 0; i < repeat; i++) {
size_t capacity = initSize;
int* arr1 = new int[initSize];
int* arr2 = new int[initSize];
int* arr3 = new int[initSize];
for (size_t i = 0; i < initSize; i++)
{
arr1[i] = arr2[i] = arr3[i] = rand() % 21;
}
size_t size = initSize;
for (int j = 0; j < N; j++)
{
int newSize = size + addSize;
start = clock();
arr1 = resizeMemCpy(arr1, size, newSize);
end = clock();
clocksMemCpy += double(end) - start;
start = clock();
arr2 = resizeCopy(arr2, size, newSize);
end = clock();
clocksCopy += double(end) - start;
start = clock();
arr3 = resizeCapacity(arr3, size, newSize, &capacity);
end = clock();
clocksCapacity += double(end) - start;
size = newSize;
}
checkEqual(arr1, arr2, arr3, size);
delete[] arr1;
delete[] arr2;
delete[] arr3;
}
cout << "initial size: " << initSize << ", add size: " << addSize << ", iterations: " << N << ", repeat: " << repeat
<< ", memcpy alg: " << clocksMemCpy / CLOCKS_PER_SEC << " sec"
<< ", copy alg: " << clocksCopy / CLOCKS_PER_SEC << " sec"
<< ", capacity alg: " << clocksCapacity / CLOCKS_PER_SEC << " sec"
<< endl;
}
catch (const exception& ex) {
cerr << ex.what() << endl;
}
return 0;
}