2d array A[][] is the same as **A, right?

S

spasmous

I'm getting an error when using a C program that accepts **float as
arguments in my C++ code. Here the code (short):

float A[3][3] = {0,0,0,1,2,0,3,4,0};
float W[3] = {0,0,0};
float V[3][3] = {0,0,0,0,0,0,0,0,0};

svdcmp(A,2,2,W,V);

where the function svdcmp is void svdcmp(float **a, int m, int n, float
w[], float **v).

The compiler (MSVC++) message is:
Error C2664: 'svdcmp' : cannot convert parameter 1 from 'float [3][3]'
to 'float ** '. Types pointed to are unrelated; conversion requires
reinterpret_cast, C-style cast or function-style cast

I'm sure I'm making a blunder somewhere but it's so long since I've
used either C or C++...! Thanks for any help.
 
V

Victor Bazarov

I'm getting an error when using a C program that accepts **float as
arguments in my C++ code. Here the code (short):

float A[3][3] = {0,0,0,1,2,0,3,4,0};
float W[3] = {0,0,0};
float V[3][3] = {0,0,0,0,0,0,0,0,0};

svdcmp(A,2,2,W,V);

where the function svdcmp is void svdcmp(float **a, int m, int n, float
w[], float **v).

The compiler (MSVC++) message is:
Error C2664: 'svdcmp' : cannot convert parameter 1 from 'float [3][3]'
to 'float ** '. Types pointed to are unrelated; conversion requires
reinterpret_cast, C-style cast or function-style cast

I'm sure I'm making a blunder somewhere but it's so long since I've
used either C or C++...! Thanks for any help.

A two-dimensional array of T (T [N][M]) is not convertible to a pointer
to a pointer to T. Period.

Do not do reinterpret_cast either because it won't work. The types do
_not_ have the same data layout in memory. The only thing that is kind
of similar is that you can use operator[] on both, and the resulting
type allows you to use operator[] again, and the result is T&. But the
main difference is that the former type yields 'array of T' when you
use operator[], and the latter yields 'a pointer to T'.

If you have control over how 'svdcmp' is written, and you want to keep
it working for both T** and T[][], make two templates out of it. One
will have T[N][M] as the argument type, the other will have T**.

If you don't have control over 'svdcmp', and you just have to convert
your arrays into a pointer to pointers, then you'll need to create some
temporary arrays of pointers and pass them:

float A[3][3] = { ...
float V[3][3] = { ...

float *pA[] = { &A[0][0], &A[1][0], &A[2][0] };
float *pV[] = { &V[0][0], &V[1][0], &V[2][0] };

svdcmp(pA,2,2,W,pV);

Now, without knowing more I can't vouch for the functionality being up
to your needs, but it should at least give you an idea.

V
 
A

Allan Bruce

I'm getting an error when using a C program that accepts **float as
arguments in my C++ code. Here the code (short):

float A[3][3] = {0,0,0,1,2,0,3,4,0};
float W[3] = {0,0,0};
float V[3][3] = {0,0,0,0,0,0,0,0,0};

svdcmp(A,2,2,W,V);

where the function svdcmp is void svdcmp(float **a, int m, int n, float
w[], float **v).

The compiler (MSVC++) message is:
Error C2664: 'svdcmp' : cannot convert parameter 1 from 'float [3][3]'
to 'float ** '. Types pointed to are unrelated; conversion requires
reinterpret_cast, C-style cast or function-style cast

I'm sure I'm making a blunder somewhere but it's so long since I've
used either C or C++...! Thanks for any help.

No, no no 2D array is not the same as a pointer to pointer - think of it
this way, an array is a contiguous set of data, so declaring float[3][3]
will occupy 3*3*sizeof(float) contigous bytes of memory. Pointers can point
*anywhere* and it is likely that they will if they were allocated at
different points in the program.
Allan
 
S

spasmous

Victor said:
...
If you have control over how 'svdcmp' is written, and you want to keep
it working for both T** and T[][], make two templates out of it. One
will have T[N][M] as the argument type, the other will have T**.
...

Ah, thanks for the tips. I do have the source code for svdcmp() - I'd
like to modify it to accept *a (much more convenient) rather than **a
or a[][]. Just a sanity check - in the code wherever it says a[j][k]
then I need to change this to a[j*N+k] (or a[k*N+j], whatever you know
what I mean :) where N is the length of that dimension.
 
K

kawahee

you only need a single pointer, and then you can access it however u
like.

#define WIDTH 5
#define HEIGHT 5

#define ACCESS(ptr, x, y) (ptr[(y*WIDTH)+x])

float array[WIDTH][HEIGHT] = { .... };
float *parray = array;

ACCESS(parry, 1, 1); // same as array[1][1]
 
R

Richard Herring

Victor Bazarov said:
I'm getting an error when using a C program that accepts **float as
arguments in my C++ code. Here the code (short):

float A[3][3] = {0,0,0,1,2,0,3,4,0};
float W[3] = {0,0,0};
float V[3][3] = {0,0,0,0,0,0,0,0,0};

svdcmp(A,2,2,W,V);

where the function svdcmp is void svdcmp(float **a, int m, int n, float
w[], float **v).

The compiler (MSVC++) message is:
Error C2664: 'svdcmp' : cannot convert parameter 1 from 'float [3][3]'
to 'float ** '. Types pointed to are unrelated; conversion requires
reinterpret_cast, C-style cast or function-style cast

I'm sure I'm making a blunder somewhere but it's so long since I've
used either C or C++...! Thanks for any help.

A two-dimensional array of T (T [N][M]) is not convertible to a pointer
to a pointer to T. Period.

Do not do reinterpret_cast either because it won't work. The types do
_not_ have the same data layout in memory. The only thing that is kind
of similar is that you can use operator[] on both, and the resulting
type allows you to use operator[] again, and the result is T&. But the
main difference is that the former type yields 'array of T' when you
use operator[], and the latter yields 'a pointer to T'.

If you have control over how 'svdcmp' is written, and you want to keep
it working for both T** and T[][], make two templates out of it. One
will have T[N][M] as the argument type, the other will have T**.

Better still, define a template "matrix traits" class which encapsulates
the concept of Matrix and provides typedefs for things like value_type
and reference, and static functions for element access and size, and
specialise that for different argument types. Then template svdcmp on
generic Matrix types deduced from its arguments. Now you can add new
Matrix representations without having to make any changes to the code of
svdcmp.

// Untested code

template <class M>
struct MatrixTraits
{
/* assume that by default this will be instanced with M as some kind of
Matrix class which already provides all the needed functionality:
*/
typedef M matrix_type;
typedef typename M::value_type value_type;
typedef typename M::reference reference;
static reference element(matrix_type & m, size_t i, size_t j)
{ return m(i, j); }
static value_type element(matrix_type const & m, size_t i, size_t j)
{ return m(i, j); }
static size_t width(matrix_type & m) { return m.width(); }
static size_t height(matrix_type & m) { return m.height(); }
// etc...
};

// specialise for array of array
template <class T, size_t M, size_t N>
struct MatrixTraits <T[M][N]>
{
typedef T value_type;
typedef T & reference;
typedef T matrix_type[M][N];
static reference element(matrix_type & m, size_t i, size_t j)
{ return m[j]; }
static value_type element(matrix_type const & m, size_t i, size_t j)
{ return m[j]; }
static size_t width(matrix_type & m) { return M; }
static size_t height(matrix_type & m) { return N; }
// etc...
};

typedef typename M::value_type value_type;
static value_type element(M & m, size_T i, size_t j) { return m(i, j); }
static size_t width(M & m) { return m.width(); }
static size_t height(M & m) { return m.height(); }
// etc...
};

template <class A, class V, class W>
void svdcmp(A & a, V & v, W & w)
{
typedef MatrixTraits<A> at;
typedef MatrixTraits<V> vt;
typedef MatrixTraits<W> wt;

size_t const m = at::width(a);
size_t const n = at::height(a);
for (size_t i = 0; i<m; ++i)
for (size_t j = 0; i<n; ++i)
{
at::value_type a_ij = at::element(a, i, j);
/etc.../
}
}

Or something like that.
If you don't have control over 'svdcmp', and you just have to convert
your arrays into a pointer to pointers, then you'll need to create some
temporary arrays of pointers and pass them:

float A[3][3] = { ...
float V[3][3] = { ...

float *pA[] = { &A[0][0], &A[1][0], &A[2][0] };
float *pV[] = { &V[0][0], &V[1][0], &V[2][0] };

svdcmp(pA,2,2,W,pV);

Now, without knowing more I can't vouch for the functionality being up
to your needs, but it should at least give you an idea.

V
 
R

Richard Herring

[reposted, less scrambled formatting :-( ]
Victor Bazarov said:
I'm getting an error when using a C program that accepts **float as
arguments in my C++ code. Here the code (short):

float A[3][3] = {0,0,0,1,2,0,3,4,0};
float W[3] = {0,0,0};
float V[3][3] = {0,0,0,0,0,0,0,0,0};

svdcmp(A,2,2,W,V);

where the function svdcmp is void svdcmp(float **a, int m, int n, float
w[], float **v).

The compiler (MSVC++) message is:
Error C2664: 'svdcmp' : cannot convert parameter 1 from 'float [3][3]'
to 'float ** '. Types pointed to are unrelated; conversion requires
reinterpret_cast, C-style cast or function-style cast

I'm sure I'm making a blunder somewhere but it's so long since I've
used either C or C++...! Thanks for any help.

A two-dimensional array of T (T [N][M]) is not convertible to a pointer
to a pointer to T. Period.

Do not do reinterpret_cast either because it won't work. The types do
_not_ have the same data layout in memory. The only thing that is kind
of similar is that you can use operator[] on both, and the resulting
type allows you to use operator[] again, and the result is T&. But the
main difference is that the former type yields 'array of T' when you
use operator[], and the latter yields 'a pointer to T'.

If you have control over how 'svdcmp' is written, and you want to keep
it working for both T** and T[][], make two templates out of it. One
will have T[N][M] as the argument type, the other will have T**.

Better still, define a template "matrix traits" class which encapsulates
the concept of Matrix and provides typedefs for things like value_type
and reference, and static functions for element access and size, and
specialise that for different argument types. Then template svdcmp on
generic Matrix types deduced from its arguments. Now you can add new
Matrix representations without having to make any changes to the code of
svdcmp.

// Untested code

template <class M>
struct MatrixTraits
{
/* assume that by default this will be instanced with M as some kind of Matrix class
which already provides all the needed functionality:
*/
typedef M matrix_type;
typedef typename M::value_type value_type;
typedef typename M::reference reference;
static reference element(matrix_type & m, size_t i, size_t j)
{ return m(i, j); }
static value_type element(matrix_type const & m, size_t i, size_t j)
{ return m(i, j); }
static size_t width(matrix_type & m) { return m.width(); }
static size_t height(matrix_type & m) { return m.height(); }
// etc...
};

// specialise for array of array
template <class T, size_t M, size_t N>
struct MatrixTraits <T[M][N]>
{
typedef T value_type;
typedef T & reference;
typedef T matrix_type[M][N];
static reference element(matrix_type & m, size_t i, size_t j)
{ return m[j]; }
static value_type element(matrix_type const & m, size_t i, size_t j)
{ return m[j]; }
static size_t width(matrix_type & m) { return M; }
static size_t height(matrix_type & m) { return N; }
// etc...
};


template <class A, class V, class W>
void svdcmp(A & a, V & v, W & w)
{
typedef MatrixTraits<A> at;
typedef MatrixTraits<V> vt;
typedef MatrixTraits<W> wt;

size_t const m = at::width(a);
size_t const n = at::height(a);
for (size_t i = 0; i<m; ++i)
for (size_t j = 0; i<n; ++i)
{
at::value_type a_ij = at::element(a, i, j);
/etc.../
}
}

Or something like that.
If you don't have control over 'svdcmp', and you just have to convert
your arrays into a pointer to pointers, then you'll need to create some
temporary arrays of pointers and pass them:

float A[3][3] = { ...
float V[3][3] = { ...

float *pA[] = { &A[0][0], &A[1][0], &A[2][0] };
float *pV[] = { &V[0][0], &V[1][0], &V[2][0] };

svdcmp(pA,2,2,W,pV);

Now, without knowing more I can't vouch for the functionality being up
to your needs, but it should at least give you an idea.

V
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,770
Messages
2,569,584
Members
45,077
Latest member
SangMoor21

Latest Threads

Top