Подтвердить что ты не робот

Не двойной ли [] [] эквивалентно ** double?

Я спрашиваю об этом, потому что моя программа имеет две функции для умножения матриц, они умножают только матрицы 4x4 и 4x1. Заголовки:

 double** mult4x1(double **m1, double **m2);
 double** mult4x4(double **m1, double **m2);

Они делают m1 * m2 и возвращают его в ** double, ниже - фрагмент умножения 4x4.

 double** mult4x4(double **m1, double **m2){
      double** result = (double**) malloc(sizeof(double)*4);
      for (int i = 0; i < 4; i++) {
           result[i] = (double*) malloc(sizeof(double)*4);
      }
      ...multiply...
      return result;
 }

Разница между mult4x1 и mult4x4 заключается только в индексах, используемых внутри них.

У меня эти 3 матрицы:

double m1[4][4] = {
    {2, 3, 5, 6},
    {9, 8, 1, 7},
    {5, 4, 3, 1},
    {7, 6, 1, 2}
};

double m2[4][4] = {
    {1, 0, 0, 0},
    {0, 1, 0, 0},
    {0, 0, 1, 0},
    {0, 0, 0, 1}
};

double m3[4][1] = {
    {2},
    {3},
    {3},
    {1}
};

Пытаясь умножить эти матрицы, возникает ошибка.

double** test = mult4x4(m1, m2);
double** test2 = mult4x1(identity4x4(), m3);
//identity4x4() creates a 4x4 identity matrix - double** identity4x4();

Урожайность:

Ошибка: невозможно преобразовать double (*)[4]' to double * 'для аргумента 1' to double * mult4x4 (double *, double *)'

Ошибка: невозможно преобразовать double (*)[1]' to double * 'для аргумента 2' to double * mult4x1 (double *, double *)'

Не двойной [] [] должен быть равен ** double? Массив массивов двойных. Любые разъяснения, неправильные представления и ошибки приветствуются.

4b9b3361

Ответ 1

Нет.
A double** является указателем на указатель на double (double*).

Поэтому на самом деле он должен быть создан следующим образом (обратите внимание на дополнительный * в первом файле malloc sizeof()):

  double** result = (double**) malloc(sizeof(double*)*4);
  for (int i = 0; i < 4; i++) {
       result[i] = (double*) malloc(sizeof(double)*4);
  }

Итак, в памяти это будет выглядеть так:

[] -> { d,d,d,d }
[] -> { d,d,d,d }
[] -> { d,d,d,d }
[] -> { d,d,d,d }

Есть 4 буфера, которые содержат 4 двойника, но не являются непрерывными.

Хотя ваш двойной [4] [4] является непрерывным буфером в памяти, например:

 { { d,d,d,d } { d,d,d,d } {d,d,d,d} {d,d,d,d} }

Ответ 2

Хотя оба double[N][M] и double** позволяют вам работать с 2D-массивами, они, безусловно, не эквивалентны: первый представляет собой 2D-массив из double s, а позже представляет собой указатель на указатель на double, который может быть интерпретирован (с помощью удобного синтаксиса квадратной скобки C/С++) в виде массива указателей на double или как массив массивов double.

double[N][M] представляет собой 2D-массивы "прямоугольной" формы, а double** позволяет создавать массивы "свободной формы" (зубчатые), выделяя разные объемы памяти каждой строке вашей матрицы.

Разница с компилятором заключается в том, что данный double[N][M] и пара целых чисел {r,c} он может вычислять местоположение элемента, вычисляя смещение от начала массива, не читая ничего из памяти. Однако при использовании double** компилятор должен вычислить адрес указателя на строку, прочитать этот указатель и только затем вычислить адрес целевого элемента. Из-за этой разницы эти два не являются взаимозаменяемыми.

Ответ 3

Нет типа [][]. На самом деле у вас есть m2, который представляет собой массив массивов размером 4 типа double и m1, который представляет собой массив массивов размером 1. Массив массивов размера 4 не эквивалентен двойному указателю.

Ответ 4

Ну, надеюсь, я не буду здесь глупым, но нотация double [][] также используется, когда вы обращаетесь к непрерывному блоку памяти, а double** не обязательно непрерывна.

Я думаю, что это причина ошибки. Даже если вы можете использовать одну и ту же семантику для доступа к значениям, они на самом деле разные типы.

Ответ 5

[] [] не эквивалентен **; double ** var; - указатель указателей, и, как вы можете видеть из вашего выделения в памяти, вы держите массив указателей, а каждый указатель внутри указывает на массив значений double

double var [4][4]; хранится в памяти на месте и несколько эквивалентен double *; В этом случае знает размер матрицы (4 x 4), поэтому, например, при использовании var[2][2], он знает, где находится то, что находится в памяти; var[x][y] переводится примерно так: var[x + y * 4] и декларация может быть интерпретирована как double var [16];

Raxvan.

Ответ 6

Нет, это не так. double[n][m] выделяет один блок памяти, достаточно большой для вашего двухмерного массива. Затем вы получаете возможность не вычислять собственную индексацию. При передаче двумерного массива в функцию компилятор требует от вас указать размер внутреннего измерения, чтобы он мог обработать индексирование.

double** является указателем на указатель. Так как C допускает арифметику указателей, это может означать массив указателей, где каждый указатель указывает на массив двойников. Значения сами по себе не должны находиться в непрерывном блоке памяти. Как вы можете видеть, они совсем другие звери.

Если у вас есть double[n][m] и вы хотите передать его в double **, вам нужно будет создать свой собственный индексный массив.

Ответ 7

Нет... m1 - это массив с четырьмя элементами, каждый из которых представляет собой массив из четырех элементов. То же самое с m2. Даже если первый "уровень" распадается из массива в указатель, второй "уровень" не будет. Вопрос в том, почему? Давайте посмотрим на некоторый код:

/* double[4][4] implicitly converts to double(*)[4]
 * giving you a pointer to first element of m1 so
 * you get back an array of four doubles.
 */
double (*pm1a)[4] = m1[0];

/* This isn't right, but let pretend that it was
 * and that what you got back was a pointer
 * to a pointer that pointed to m1 properly.
 */
double **pm1b = (double **)m1[0];

Итак, что произойдет с нашим гипотетическим кодом, если мы будем делать pm1a[1] и pm1b[1]?

pm1a[1] отлично: он будет правильно продвигать pm1a на 4 * sizeof(double) (так как указатель указывает на double[4]).

pm1b[1], с другой стороны, сломается: он будет продвигаться на неправильную сумму: размер указателя на double.

Но это еще не все. Там еще более тонкая ошибка. Если оба измерения должны были распадаться, компилятор не мог знать, что к массиву обращаются. Он будет счастливо интерпретировать pm1b[1] как указатель на двойник. И что тогда происходит? Это займет какое-либо значение double, сохраненное в этом месте, и обработает его как указатель на double.

Вы можете понять, почему это было бы катастрофой.

Ответ 8

Другое отличие состоит в том, что вы не можете сделать double, чтобы указать на любой другой адрес памяти, если вы объявите его как double [] [] (что-то вроде финального поля)

Но если вы объявите его как ** double, тогда он может указывать на любую ячейку памяти.

Ответ 9

Нет, они определенно не эквивалентны, первый представляет двумерный массив удвоений, а последний представляет собой указатель на указатель на double.