问题
I have such matrix in my program:
double m[3][4] =
{
{2, 4, 5, 7},
{4, 5, 1, 12},
{9, 12, 13, -4}
};
And I'd like to cast it to double**
type.
I've already tried simple double** a = (double**)m;
, but it doesn't work (when I try to read any value, I get "Access violation reading location 0x00000000.", which means I'm trying to read from NULL
adress.
I found almost working solution:
double *b = &m[0][0];
double **c = &b;
It works when I read field c[0][any]
But same NULL adress reading problem occurs, when I try to read value from field c[1][0]
.
What is the proper way to cast my double m[3][4]
array to type double**
?
edit: You say that's impossible. So I'll change a problem a little bit. How can I pass two-dimensional double array as a parameter to a function? My function has prototype:
void calculate(double **matrix, int n); //where matrix size is always n by n+1
And it's working fine with dynamically-allocated arrays. I doubt that only way to make it work is allocating new dynamical array and copy original static array one element by another...
回答1:
You can't just cast the array. You are going to have to create something like this:
double m[3][4] =
{
{2, 4, 5, 7},
{4, 5, 1, 12},
{9, 12, 13, -4}
};
double *marray[3] = {m[0],m[1],m[2]};
calculate(marray,3);
Or you can use a loop:
const size_t n = 3;
double *marray[n];
for (size_t i=0; i!=n; ++i) {
marray[i] = m[i];
}
calculate(marray,n);
回答2:
You can't.
The notation double**
refers to an array of pointers. You don't have an array of pointers, you have an array of arrays of doubles.
回答3:
When you write
double m[3][4]
{
{2, 4, 5, 7},
{4, 5, 1, 12},
{9, 12, 13, -4}
};
The compiler actually creates an array of doubles as if you had written
double _m[] = {2, 4, 5, 7, 4, 5, 1, 12, 9, 12, 13, -4};
However, thanks to C/C++ type system, the compiler remembers that m
's type
is double [3][4]
. In particular it remembers the sizes 3 and 4.
When you write
m[i][j]
the compiler replaces it by
_m[i * 4 + j];
(The 4
comes from the second size in double [3][4]
.) For instance,
m[1][2] == 1
and _m[1 * 4 + 2] == _m[6] == 1
as well.
As others said, a double**
is a different type which doesn't carry the
sizes with it. To consider double** a
as a 3 x 4 matrix, a[0]
, a[1]
and
a[2]
must be pointers to double
(that is, double*
) pointing to the
first element of the corresponding row. You can achieve this with
double* rows[] = { &m[0][0], &m[1][0], &m[2][0] };
double** a = &rows[0];
A simple cast doesn't create the variable rows
above. Let me present other
alternative (but equivalent) ways to define rows
double* rows[] = { &m[0][0], &m[0][0] + 4, &m[0][0] + 2 * 4};
double* rows[] = { &_m[0], &_m[4], &_m[2 * 4]};
As you can see, only the second size (i.e. 4
) is necessary. In general, for
multi-dimensional arrays, all sizes but the first are required. For this
reason a 1-dimensional array
double x[4] = { 1, 2, 3, 4 };
can be implicitly converted to a double*
double* y = x;
Using this fact we can also write
double* rows[] = { _m, _m + 4, _m + 2 * 4};
Indeed, _m
is converted to a double*
pointing to m[0]
. Then, in _m + 4
,
_m
is is converted to a double*
pointing to m[0]
and to this pointer
it's added 4
. Hence, _m + 4
is a pointer the fourth double following
_m[0]
, which is _m[4]
and so on.
So far I have explained why you cannot cast a double [3][4]
(or any other sizes) to a double**
. Now, I'shall show, in your particular case, how calculate can be defined.
template <int N>
void calculate(double (&m)[N][N+1]) {
// use m as a double[N][N+1]
}
You call
calculate(m);
and the compiler will deduce the size N
for you. In general (i.e, when the second dimension is not the N + 1
) you can write
template <int N, int M>
void calculate(double (&m)[N][M]) {
// use m as a double[N][M]
}
回答4:
If you're always using arrays (no pointers) for initialization, and you are able to avoid the pointer stuff in your calculate function, you might consider the following option, which uses size deduction by templates.
template<int m, int n>
void doubleFunc(double (&mat)[m][n])
{
for (auto i = 0; i < m; i++)
{
for (auto j = 0; j < n; j++)
{
std::cout << mat[i][j] << std::endl;
}
}
}
It worked during my quick test.
double m[3][4] =
{
{2, 4, 5, 7},
{4, 5, 1, 12},
{9, 12, 13, -4}
};
doubleFunc(m);
回答5:
You can pass a 2d array as a function parameter:
void calculate(double matrix[][y], int n);
回答6:
Until variable-length arrays are in the C++ standard, your choices include:
- If your compiler supports variable-length arrays as an extension, you can likely pass them with a function declaration such as
void foo(std::size_t n, double a[][n+1])
. Note that the compiler likely requiresn
to be passed before a parameter declaration that usesn
or requires some special syntax. - You can pass a
double *
and do index arithmetic manually in the function:void foo(std::size_t n, double *a) { … a[row*(n+1) + column] … }
- You can create a class the implements variable-length arrays by doing the index arithmetic in its accessor functions.
- You can allocate space for
n
pointers todouble
, fill those pointers with pointers to each row of the array, and pass the address of the space.
来源:https://stackoverflow.com/questions/15766382/c-casting-static-two-dimensional-double-array-to-double