Есть ли способ инициализировать массив с непостоянными переменными? (С++)
Я пытаюсь создать класс как таковой:
class CLASS
{
public:
//stuff
private:
int x, y;
char array[x][y];
};
Конечно, он не работает, пока я не изменю int x, y;
на
const static int x = 10, y = 10;
Это непрактично, потому что я пытаюсь прочитать значения x и y из файла. Итак, есть ли способ инициализировать массив с неконстантными значениями или объявить массив и объявить его размер для разных операторов? И я знаю, что это, вероятно, потребует создания класса массива, но я не уверен, с чего начать, и я не хочу создавать динамический список 2D, когда сам массив не является динамическим, просто размер не известно во время компиляции.
Ответы
Ответ 1
Компилятор должен иметь точный размер класса при компиляции, вам придется использовать новый оператор для динамического выделения памяти.
Переключить массив char [x] [y]; к массиву char **; и инициализируйте свой массив в конструкторе, и не забудьте удалить свой массив в деструкторе.
class MyClass
{
public:
MyClass() {
x = 10; //read from file
y = 10; //read from file
allocate(x, y);
}
MyClass( const MyClass& otherClass ) {
x = otherClass.x;
y = otherClass.y;
allocate(x, y);
// This can be replace by a memcopy
for( int i=0 ; i<x ; ++i )
for( int j=0 ; j<x ; ++j )
array[i][j] = otherClass.array[i][j];
}
~MyClass(){
deleteMe();
}
void allocate( int x, int y){
array = new char*[x];
for( int i = 0; i < y; i++ )
array[i] = new char[y];
}
void deleteMe(){
for (int i = 0; i < y; i++)
delete[] array[i];
delete[] array;
}
MyClass& operator= (const MyClass& otherClass)
{
if( this != &otherClass )
{
deleteMe();
x = otherClass.x;
y = otherClass.y;
allocate(x, y);
for( int i=0 ; i<x ; ++i )
for( int j=0 ; j<y ; ++j )
array[i][j] = otherClass.array[i][j];
}
return *this;
}
private:
int x, y;
char** array;
};
* EDIT:
У меня был конструктор копирования
и оператор присваивания
Ответ 2
использовать вектор.
#include <vector>
class YourClass
{
public:
YourClass()
: x(read_x_from_file()), y(read_y_from_file())
{
my_array.resize(x);
for(int ix = 0; ix < x; ++ix)
my_array[ix].resize(y);
}
//stuff
private:
int x, y;
std::vector<std::vector<char> > my_array;
};
Ответ 3
Не таким образом, как и в С++, размеры массива c-стиля должны быть известны во время компиляции, причем некоторые расширения для конкретного поставщика допускают определенные размеры времени выполнения (для повышения совместимости с C99), но не в ситуации, которую вы описываете (если вас это интересует, здесь описание). Проще всего сделать следующее:
std::vector< std::vector<char> > array;
И примените размер в конструкторе:
array.resize(x);
for(std::vector< std::vector<char> >::iterator curr(array.begin()),end(array.end());curr!=end;++curr){
curr->resize(y);
}
Есть много преимуществ векторных над стилями типа c, см. здесь
Ответ 4
Поместите всю память в один блок.
Поскольку он является частным, вы можете затем получить свои методы доступа для получения правильного значения.
Быстрый пример:
#include <vector>
#include <iostream>
class Matrix
{
public:
class Row
{
public:
Row(Matrix& p,unsigned int x)
:parent(p)
,xAxis(x)
{}
char& operator[](int yAxis)
{
return parent.data(xAxis,yAxis);
}
private:
Matrix& parent;
unsigned int xAxis;
};
Matrix(unsigned int x,unsigned int y)
:xSize(x)
,ySize(y)
,dataArray(x*y)
{}
Matrix::Row operator[](unsigned int xAxis)
{
return Row(*this,xAxis);
}
char& data(unsigned int xAxis,unsigned int yAxis)
{
return dataArray[yAxis*xSize + xAxis];
}
private:
unsigned int xSize;
unsigned int ySize;
std::vector<char> dataArray;
};
int main()
{
Matrix two(2,2);
two[0][0] = '1';
two[0][1] = '2';
two[1][0] = '3';
two[1][1] = '4';
std::cout << two[1][0] << "\n";
std::cout << two.data(1,0) << "\n";
}
Ответ 5
Взгляните на boost:: multi_array.
Ответ 6
Вы не можете объявлять или инициализировать глобальный или статический массив декларативно, используя непостоянные значения (время компиляции). Это возможно для локальных массивов (массивы с переменным размером C99, поскольку их инициализатор по существу работает во время выполнения каждый раз, когда функция выполняется).
Для вашей ситуации я предлагаю использовать указатель вместо массива и динамически создавать фактический массив во время выполнения (используя new
):
class CLASS
{
public:
CLASS(int _x, int _y) : x(_x), y(_y) {
array = new char*[x];
for(int i = 0; i < x; ++i)
array[i] = new char[y];
}
~CLASS() {
for (int i = 0; i < x; ++i)
delete[] array[i];
delete[] array;
}
//stuff
private:
int x, y;
char **array;
};
Ответ 7
Вы можете выделить память для вашего 2-мерного массива в конструкторе и освободить его в деструкторе. Самый простой способ:
array = (char **)malloc(sizeof(char *) * x);
if (array) {
for (i = 0; i < x; i++) {
array[i] = (char *)malloc(sizeof(char) * y);
assert(array[i]);
}
}
Ответ 8
Если размер не известен во время компиляции, массив является динамическим. То, что вы можете сделать, чтобы сохранить его статичным, состоит в том, чтобы сделать их больше, чем ваш самый ожидаемый размер.
Ответ 9
Если вам нужен массив динамического размера как член класса, вам нужно массировать new
его и присваивать этому значению указателю. Синтаксис char array[size]
предназначен только для массивов статического размера.
Еще лучше, вы действительно должны использовать std::vector< std::vector<char> >
, в настоящее время очень мало причин для ручной работы с массивами с динамическим размером.