C ++ Динамические / Статические массивы как параметры для функций - PullRequest
1 голос
/ 04 марта 2012

Я пытался использовать 2D-массив в качестве параметра для конструктора в моем классе C ++.

Заголовок:

Matrix::Matrix(double **initComponents, int rows, int columns)

Если я просто продолжу делать регулярные вызовы новых и инициализировать вложенные массивы, передам указатель на конструктор, все хорошо, НО я думал, могу ли я просто создать статический 2D-массив с инициализатором и передать указатель на него, конструктору?

double A[][3] = { {2.0, 3.0, 4.0} , {1.0, 3.0, 4.0} , {2.0, 3.0, 4.0} }; 
Matrix *mtx = new Matrix(A, 3, 3);

что не работает: (

Компилятор MS Visual Studio:

" error C2664: 'Matrix::Matrix(double **,int,int)' : cannot convert parameter 1 from 'double [3][3]' to 'double ** "

Может кто-нибудь объяснить, почему? Я думал, что это сделает автоматическое преобразование между ссылкой и указателем.

Второй вопрос: почему я могу просто объявить A как двойное A[][], почему я должен указать второе измерение, хотя я указываю все значения.

1 Ответ

5 голосов
/ 04 марта 2012

Массив конвертируется в указатель, но он работает только для одного уровня. Массив массивов не преобразуется в указатель на указатели.

Массив можно преобразовать в указатель, поскольку указатель все еще обеспечивает разумный способ поиска значений массива, но массив массивов - это принципиально иная вещь, чем указатель на указатели. Массив массивов хранится в памяти непрерывно. Например, если у вас было такое определение:

int a[2][2] = {{1,2},{3,4}};

Затем [0] [0] сохраняется в первой ячейке памяти, a [0] [1] сохраняется во второй, a [1] [0] в третьей и a [1] [1] ] в четвертом. Когда вы хотите посмотреть конкретный элемент, например, [i] [j], компилятор может вычислить местоположение, так как он знает размер массивов:

int value = ((int *)a)[i*2+j];

Сравните это с указателем на указатели

* * 1010

Теперь, когда вы используете [i] [j], компилятор не может напрямую знать, где искать. Сначала нужно взглянуть на [0] и посмотреть, куда это указывает, а затем посмотреть во второй раз, чтобы найти значение.

int *ap = a[i];
int value = ap[j];

Поскольку компилятор должен использовать другой способ поиска значений в массивах массивов и указателей на указатели, вы не можете использовать их взаимозаменяемо.

Аналогично, в таком объявлении:

int a[][2] = {{1,2},{3,4}};

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

Если вы действительно хотите иметь возможность передавать 2D-массив, вы можете сделать это с помощью шаблонного конструктора, например:

template<int rows, int cols>
Matrix(const double (&initComponents)[rows][cols])
{
  // initialize matrix elements here
}

И тогда вам даже не нужно явно передавать размер:

double A[][3] = { {2.0, 3.0, 4.0} , {1.0, 3.0, 4.0} , {2.0, 3.0, 4.0} };
Matrix *mtx = new Matrix(A);
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...