2014-02-12 6 views
5

У меня есть функция, которая принимает 3 параметра, первая - ** двойная.Невозможно преобразовать double [] [] в double **

normalizeDataZeroMeanUnitSD(double ** trainingActions, int numberOfTrainingActions, int descriptorDimension) 

Когда я зову его из основной, я пытаюсь использовать normalizeDataZeroMeanUnitSD (данные, 681, 24); Однако, я получаю

cannot convert parameter 1 from 'double [681][24]' to 'double **' 

Это, как я построить массив данных:

fstream infile; 
infile.open("gabor\\Data.txt"); 

double data[681][24]; 

while (!infile.eof()) 
    { 
     for(int j=0;j<681;j++) 
     { 
      for(int k=0; k<24;k++) 
      { 

       infile >> data[j][k]; 

      } 

     } 

} 
infile.close(); 

Есть ли способ сделать то же самое, используя ** данные?

+0

Возможный дубликат [Как использовать массивы в C++?] (Http://stackoverflow.com/questions/4810664/how-do-i-use-arrays-in-c) – Angew

ответ

2

Используйте любое из следующих объявлений. Оба эквивалентны.

NormalizeDataZeroMeanUnitSD(double trainingActions[][24], int numberOfTrainingActions, int descriptorDimension) 

NormalizeDataZeroMeanUnitSD(double trainingActions[681][24], int numberOfTrainingActions, int descriptorDimension) 

Когда вы объявляете 2D-массив, он занимает смежные области памяти. Поэтому вам нужно указать, по крайней мере, количество столбцов (в случае основной архитектуры строки).

Для определения основных основных и столбцовых определений см. this.

Для вашего отредактированного вопроса, да, вы можете объявить, используя **data. Динамически выделяем массив data. Но не забудьте освободить его, когда закончите с ним.

double **data=new double*[681]; 
for (int i=0;i<681;i++) 
{ 
    data[i]=new double[24]; 
} 

//do what you want to do 


for (int i=0;i<681;i++) 
{ 
    delete [] data[i]; 
} 

delete [] data; 

Теперь ваш прототип функции может быть как void func(double **pp), потому что data является указателем не 2D массива.

+0

Ваши две декларации эквивалентны ... – Jarod42

+0

@ Jarod42, конечно, –

+0

Второй такой вводящий в заблуждение, передайте по ссылке вместо указателя. – Jarod42

3

2-й массив - это непрерывная область хранения. Функция ожидает указатель на указатели. Они несовместимы.

+0

Хорошо, но как я могу преодолеть это имеет 2d двойной массив? –

+0

@snakeplissken: вам нужно создать массив из 681 'double *' и инициализировать каждый из них указателем на одну строку вашего 2-D массива. –

2

double[][] не то же самое, что double**.

double** является указателем на указатели. double[][] - это двумерный массив, выделенный как непрерывное хранилище.

Чтобы передать функцию «2-мерный массив», вам необходимо создать массив указателей на массивы. Например:

double* array_2d[681]; 
for(unsigned int i=0; i<681; ++i) { 
    array_2d[i] = new double[24]; 
} 
normalizeDataZeroMeanUnitSD(array_2d, 681, 24); 

Не забудьте потом удалить [] каждый элемент array_2d!

Еще не изменилось, измените normalizeDataZeroMeanUnitSD, чтобы получить ссылку на std::vector<std::vector<double>>, и вам больше не нужно беспокоиться об управлении памятью и передавать правильные размеры функции.

6

Ошибка довольно ясна: Тип данных double [681][24] - это не то же самое, что и double **. Хотя верно, что double[681] может распадаться на указатель на его первый элемент (таким образом, double*), это не означает, что double[681][24] может затухать до double**.

Подумайте об этом так: double** подразумевает указатель на многие указатели. Но у double[][] нет ЛЮБОГО указателя. В лучшем случае массив ЛЮБЫХ измерений по-прежнему имеет только один указатель: к началу его непрерывного хранения.

3

Функция ожидает массив указателей на массивы; у вас есть массив массивов. Возможны следующие варианты:

  • изменить функцию, чтобы выбрать более удобный тип, возможно double*, указывающий на первый элемент смежного двумерного массива; или
  • построить отдельный массив указателей, указывающих на каждую строку вашего двумерного массива; или
  • реструктурируйте свои данные в массив указателей на массивы.
3

Вот конструктивный ответ о том, как заставить его работать.

В принципе, вам нужно создать массив с указателями на каждый 1D-фрагмент вашего 2D-массива.

double data[N][M] = {...}; 
double *dataPtrs[N]; 

for(size_t n=0; n<N; ++n) { 
    dataPtrs[n] = data[n]; 
} 

normalizeDataZeroMeanUnitSD(dataPtrs, N, M); // order of N and M might be wrong 
3

Yay, я расскажу об этом еще раз.

В C++, несмотря на аналогичный синтаксис, 2D-массивы НЕ являются зубчатыми массивами. 2D массивы (double foo[681][24]) распределены смежно в памяти. Когда вы оцениваете 2D-массив (foo[j][i]), он на самом деле делает * (foo + 24 * i + j). Все это делается под капотом. sizeof(foo)==sizeof(double)*681*24. (double** bar;). Это куча разных массивов: во-первых, вы выделяете массив указателей, длиной 268 членов. Каждый указатель указывает на массив из двух пар, длиной 24 элемента. Бар - это просто указатель, поэтому sizeof(bar)==sizeof(void*).

Более раздражающе, 2D-массивы (или статические массивы любого измерения) ведут себя противоположно всем другим типам на C++ в следующем разрешении: они передаются неявно по ссылке, вызывая странное явление ниже.

void foo(double bar[24][24]) { std::cout << sizeof(bar) << std::endl;} 
int main() { 
    double test[24][24]; 
    std::cout << sizeof(test) << std::endl;//returns sizeof(double)*24*24 
    foo(test);//returns sizeof(void*), implicitly passed by reference, opossite of the rest of c++! 
+0

Массивы любого измерения передаются как указатель на первый элемент (который в случае двухмерного массива будет иметь тип указателя на массив). Это действительно раздражает, хотя это не относится к 2-D массивам. –

+0

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

+0

@SteveJessop да, хорошее разъяснение, я отредактирую свой ответ – IdeaHat

4

Вы можете использовать шаблон:

template<std::size_t M, std::size_t N> 
void normalizeDataZeroMeanUnitSD(double (&trainingActions)[M][N], int descriptorDimension) 
{ 
    for(std::size_t m = 0; m < M; ++m) 
    { 
     for(std::size_t n = 0; n < N; ++n) 
     { 
      trainingActions[m][n] = ...; 
     } 
    } 
} 

Но остерегайтесь кода наворотов, если вы звоните в этом со многими различных размеров массивов.

+1

+1; это, вероятно, лучшее решение. И я не стал бы волноваться о раздувании: если вам это нужно, вам это нужно. IMO. Это намного проще, чем передача аргументов 'double *' и two размерных размеров. – tenfour

+0

«Код bloat» - не совсем подходящий термин здесь, поскольку компилятор добавляет вам необходимый код. Вы правы, что это может привести к увеличению размера исполняемого файла. Однако реальная проблема заключается в том, что вам нужно знать размер во время компиляции, что может оказаться невозможным. –

+1

Пропустить массив по ссылке, поэтому можно вывести 'M'. – Jarod42

Смежные вопросы