snake plissken
snake plissken

Reputation: 2669

Cannot convert double [] [] to double **

I ve got a function that takes 3 parameteres, first one is **double.

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

When I call it from main, I am trying to use normalizeDataZeroMeanUnitSD(data, 681, 24); however, I am receiving

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

This is how I construct the data array:

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();

Is there a way to do the same using **data?

Upvotes: 5

Views: 11665

Answers (8)

HelloWorld123456789
HelloWorld123456789

Reputation: 5369

Use any of the following declarations. Both are equivalent.

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

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

When you declare a 2D array it takes up contiguous memory locations. So you need to specify at least the number of columns (in case of row major architecture).

For row major and column major definitions, have a look at this.

For your edited question, yes you can declare using **data. Dynamically allocate the data array. But remember to free it when you're done with it.

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;

Now your function prototype can be like void func(double **pp) because data is a pointer not a 2D array.

Upvotes: 3

metal
metal

Reputation: 6332

You could use a template:

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] = ...;
      }
   }
}

But beware of code bloat if you call this with many differently sized arrays.

Upvotes: 4

IdeaHat
IdeaHat

Reputation: 7881

Yay, I get to rant about this again.

In C++, despite having similar syntax, 2D arrays are NOT jagged arrays. 2D arrays (double foo[681][24]) are allocated contiguously in memory. When you deference a 2D array (foo[j][i]) it actually does *(foo+24*i+j). This is all done under the hood. The sizeof(foo)==sizeof(double)*681*24.

Jagged arrays are (double** bar;). This is a bunch of different arrays: first, you allocate an array of pointer, 268 members long. Each pointer will point to an array of doubles, 24 elements long. Bar is just a pointer, so sizeof(bar)==sizeof(void*).

More annoyingly, 2D arrays (or a static array of any dimension) behave the opposite of all other types in C++ in the following reguard: they are passed implicitly by reference, causing the weird phenomenon below.

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++!

Upvotes: 3

Nicu Stiurca
Nicu Stiurca

Reputation: 8687

Here is a constructive answer for how to make it work.

Basically, you need to generate an array that has pointers to each 1D slice of your 2D array.

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

Upvotes: 3

zennehoy
zennehoy

Reputation: 6846

double[][] is not the same thing as double**.

double** is a pointer to pointers. double[][] is a 2-dimensional array allocated as continuous storage.

In order to pass a "2-dimensional array" to the function, you need to create an array of pointers to arrays. For example:

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

Remember to later delete[] each element of array_2d!

Better yet, change normalizeDataZeroMeanUnitSD to take a reference to std::vector<std::vector<double>>, and you no longer have to worry about memory management, nor passing the correct dimensions to the function.

Upvotes: 2

Mike Seymour
Mike Seymour

Reputation: 254501

The function expects an array of pointers to arrays; you have an array of arrays. Some options are:

  • change the function to take a more friendly type, perhaps double* pointing to the first element of a contiguous 2-dimensional array; or
  • build a separate array of pointers pointing to each row of your 2-dimensional array; or
  • restructure your data into an array of pointers to arrays.

Upvotes: 3

tenfour
tenfour

Reputation: 36896

The error is pretty clear: Datatype double [681][24] is not the same as double **. While it's true that double[681] can decay to a pointer to its first element (thus, double*), that does not imply that double[681][24] can decay to double**.

Think about it this way: double** implies a pointer to many pointers. But double[][] does not have ANY pointers in it. At best, an array of ANY dimensions still only has, at very most, one pointer: to the beginning of its contiguous storage.

Upvotes: 6

Sebastian Redl
Sebastian Redl

Reputation: 71999

A 2d array is a continuous area of storage. The function expects a pointer to pointers. These are incompatible.

Upvotes: 3

Related Questions