0

Я пишу программу, в которой у меня есть один класс, внутри этого класса (или снаружи, надеюсь, что это не имеет значения) У меня есть структура. В этом классе мне нужно создать массив элементов структуры (я знаю, что могу использовать вектор, например, но в программе разрешено использовать только простые динамические массивы).Как изменить размер массива элементов структуры

Я объявляю массив как T * arr[SIZE], где T - это моя структура. Единственная проблема заключается в том, что я не знаю точного размера массива и при необходимости увеличиваю его размер. Так что я написал функцию масштабирования:

if(some cond){ 
    T * tmpArr[newSIZE]; 
    memcpy(tmp, db, newSIZE*sizeof(T)); 
    delete [] arr; 
    arr = tmpArr; 
} 

Но я получаю сообщение об ошибке, что MyClass::T[....] несовместима с MyClass::T*[SIZE], который отвечает на мое arr = tmpArr выражение, которое я предполагаю.

Можете ли вы сказать мне, что я делаю неправильно? И как лучше объявить T * arr[size] или T * arr = new T[size] и как изменить размер (и освободить память из старого) в этом случае?

UPDATE:

Спасибо за ответы, я соответственно в моей программе:

T * tmp = new T[newSIZE]; 
    memcpy(tmp, db, newSIZE*sizeof(T)); 
    delete [] db; 
    db = tmp; 

И теперь я получаю странные вещи, после удаления БД и присвоение db к tmp я пытаюсь напечатать все данные, содержащиеся в БД (или TMP), что странно, что я получаю:

Smith2 Michigan ave▒ ACME, Ltd. One ACME roa▒ 
    Smit▒ Michigan ave` ACME, Ltd. One ACME roa " 

    One ACME road#@"▒▒▒▒Michigan ave`▒▒▒▒Smit▒" 

    ▒▒ ▒8 Ltd.#Michigan avenuemith4▒aF▒ 

Если я печатаю те же данные перед удалением и назначение, я буду GE t нормальный текст, который я хочу. А после в программе (как и раньше, и, возможно, это проблема с моим кодом, я получаю ошибку сегментации). Кстати, я использую structstd::string и cygwin в своих окнах. Вы знаете, в чем проблема?

+2

Ваш 'tmpArr' - это массив указателей. Это выглядит нежелательным. Но опять же, весь код немного бессмыслен. –

+0

* «Единственная проблема заключается в том, что я не знаю точного размера массива» * Вам нужно будет отслеживать этот размер самостоятельно. –

+0

Используйте 'std :: vector'. –

ответ

1

Я предполагаю, что вы пытаетесь удалить массив, созданный, как это:

T array[size]; 

Но вы не должны вызывать удаление по этому вопросу. Этот массив удаляется, когда он выходит из области видимости. Если вы хотите создать массив и освободить его после этого, вы должны использовать оператор new при объявлении массива. Если вы хотите освободить его, используйте delete.

Но в любом случае вы можете использовать std::vector вместо того, чтобы пытаться это сделать самостоятельно. Если вам интересно узнать об этом материале, была/есть сериал на канале 9 от Microsoft от Stephen T. Lavavej здесь:

http://channel9.msdn.com/Series/C9-Lectures-Stephan-T-Lavavej-Standard-Template-Library-STL-/C9-Lectures-Introduction-to-STL-with-Stephan-T-Lavavej, который является настоящим драгоценным камнем.

3
T arr[N]; 

Заявление этой формы дает массив размера N с автоматической продолжительности хранения. Это исправлено. Вы не можете изменить размер этого массива. Размер N должен быть константой времени компиляции.

T* arr = new T[N]; 

В настоящем заявлении определяется T* с автоматическим хранением. Однако он также создает массив размером N с динамическим временем хранения.Здесь размер N не обязательно должен быть константой времени компиляции.

Однако это вам не поможет. Вы все еще не можете изменить размер динамический массив. Вам нужно будет сделать delete[] arr, чтобы уничтожить старый массив, а затем сделать new T[NewSize] и как-то скопировать данные через.

Это обязательно будет беспорядочным, и на самом деле оно имеет. В вашем коде вы смешиваете два разных типа распределения. Вы пытаетесь сделать delete[] arr, хотя arr не имеет динамического хранения. Вы просто не можете этого сделать. Вы также не можете назначить один массив другому, как в arr = tmpArr;.

Вместо этого стандартная библиотека C++ предоставляет несколько типов, называемых контейнерами. Это упрощает динамически изменяемые последовательности элементов. Например, вам будет намного лучше использовать std::vector<T>.

std::vector<T> arr; 

A std::vector начинается без элементов. Вы можете добавлять элементы просто, делая arr.push_back(value). Вы также можете изменить размер вектора за один раз, выполнив arr.resize(newSize).

+0

Спасибо за ваш ответ, но можете ли вы сказать мне, как я могу изменить размер или удалить/скопировать динамический массив без каких-либо ошибок? – NGix

0

Простым решением является не изобретать квадратное колесо, а использовать уже круглый и полированный шаблон std::vector<Type> в стандартной библиотеке.

4

T* tmpArr[newSIZE]; объявляет переменную длину массив указателей до T. Обратите внимание, что массивы переменной длины не являются частью стандартного C++ (они являются частью C99, но в C++ доступны только как расширение GCC ... этот код, таким образом, несовместим с разными компиляторами).

Совершенно разумным решением было бы использовать std::vector, но так как вы сами писали, что вам запрещено использовать его, то вот что вы могли бы сделать.

  1. изменение T* tmpArr[newSIZE]; к T* arr = new T[size];
  2. теперь изменить размер массива:
    1. выделить новый массив: T* newArr = new T[newSize]
    2. копирования элементов из старого массива: memcpy(newArr, arr, size * sizeof(T))
    3. DEALLOCATE старый массив с помощью delete[]: delete[] arr
    4. с delete не меняет самого указателя, вы h пр недействительного (свисающей) указателя после шага 3, таким образом присвоить указатель на первый элемент нового массива старый: arr = newArr
  3. отслеживать размер массива, что вы работаете с

Обратите внимание, что T* arr = new T[size] выделяет память, достаточно большую для хранения объектов size типа типа T и создает этот объект с помощью конструктора по умолчанию T. Затем адрес первого элемента присваивается arr, заставляя его указывать на блок непрерывной памяти, в котором находятся эти элементы.

+1

для какой-то странной причины «memcpy», похоже, не работает в 'C++', если' T' класс с другими объектами (std :: string, например). После выделения нового массива вам нужно перебирать старый и назначать записи один за другим в новом массиве, так что вызывается по крайней мере конструктор экземпляра по умолчанию и сделайте плоскую копию. «memcpy» работает так, как ожидалось, в той же самой функции изменения размера, которая была перенесена на 'C' с помощью структуры и вместо' std :: string' a 'char [n]' или 'char * + malloc (п * SizeOf (Char)) '. – A4L

0

Предположим, что вы на самом деле хотите сохранить указатели на T. Вам нужно:

  • добавить недостающую *, так как вы направляете массив указателей на T,
  • удалить размер для tmpArr и arr

Итак:

// arr definition 
T **arr;; 

// arr resizing code 
if(some cond){ 
    T **tmpArr; 
    memcpy(tmp, db, newSIZE*sizeof(T *)); 
    delete [] arr; 
    arr = tmpArr; 
} 

Ваш массив хранит Указатели на T, а не T и tmpArr размер не известен во время компиляции, поэтому вы не можете указать его в своем типе.

Caveat: Если новый размер меньше текущего, вы потеряете указатели в конце массива. Вы должны добавить тест на это и удалить эти дополнительные T (если ваш контейнер принадлежит им) или просто выбросить исключение, так как код должен только увеличить размер массива.