I have this loop which gives seg. fault.
s->c = malloc(width * height * sizeof(double));
if (s->c == NULL) { puts("malloc failed"); exit(1); }
for (int n = 0; n < width; n++) {
for (int m = 0; m < height; m++) {
d = (&s->c)[m][n];
printf("d %f\n", d);
printf("m %i\n", m);
printf("n %i\n", n);
}
}
Inside s->c is:
double* c;
When executed it just outputs:
d 27.000000
m 0
n 0
and then seg. fault.
It worked when I treated the s->c as a 1D array, but I would really like to treat it as a 2D array.
Is that possible, when the c pointer is in a struct?
If so, is (&s->c)[m][n]
then the corr开发者_如何学JAVAect way to access the elements?
Sandra
The problem is that the compiler doesn't know the dimensions of your matrix.
When you have: double tab[m][n]
you can access the element tab[row][col]
as *(tab + (row * n) + col)
In your case you only have double *tab;
that can be considered as the pointer to the element tab[0][0]
with no information on the matrix dimensions and the compiler can't compute the right address.
You could compute the address yourself (for example using a macro) but would lose the nice tab[x][y]
syntax.
I`m surprised it compiles. You should have received at least a warning about implicitly casting a double to a pointer.
I'm very surprised it even compiles. Apparently c
is a double*
, so (&s->c)[m]
is the m'th double
. Now, double
doesn't have an operator[]
, so I don't see how the [n]
part in (&s->c)[m][n]
can be legal.
Presumably, you have declared c
differently. There are different solutions: a pointer to a pointer, an pointer to an array of doubles, an array of pointers to doubles, etcetera. All might work, if the allocations match the declaration. In your case, the allocation will not match the declaration.
The correct way to access the array elements is
d = s->c[m * width + n];
Is that what you mean by treating it as a 1D array?
Access the elements using
double d = s->c[m*width+n];
Perhaps through an inline function, to avoid unexpected behaviour.
The compiler does not know about the width of your intended 2D array. It might possibly interpret (&s->c)[m][n] as s->c[m+n], or as something quite different.
Short answer: you can't treat it as a 2D array, at least not in the way you expect.
The reason writing
(&s->c)[m][n]
doesn't work can be shown as follows. Assume the address of s->c
is 0x00080004, and the address of the dynamically allocated memory pointed to by s->c
is 0x00001000.
- The expression
(&s->c)[m][n]
is evaluated as*(*(&s->c + m) + n)
; - The expression
&s->c
evaluates to0x00080004
; - The expression
(&s->c + m)
evaluates to0x00080004+m
; - The expression
*(&s->c + m)
evaluates to the value of whatever is pointed to by0x00080004+m
. Ifm
is 0, then0x00080004+m
points to0x00001000
, which is the address of your dynamically allocated memory (*(&x) == x
). Ifm
is any other value, then0x00080004+m
points somewhere random; - The expression
(*(&s->c + m) + n)
evaluates to whatever0x00080004+m
points to offset byn
. Ifm
is 0, then the value is0x00001000+n
, or an offset into your dynamically allocated memory. Ifm
is not 0, then the value is something random; - The expression
*(*(&s->c) + m) + n)
attempts to dereference the above value. Ifm
is 0, then the result is the value of an element in the dynamically allocated array. Ifm
is not 0, then the result is ... something else. In your case, a segfault.
If you want to dynamically allocate a 2D array, you have to use a pointer to a pointer and allocate it in steps, like so:
struct {
...
double **c;
...
} *s;
...
/**
* Notes: type of s->c is double **
* type of *(s->c) and s->c[i] is double *
* type of *(s->c[i]) and s->c[i][j] is double
*/
s->c = malloc(sizeof *(s->c) * rows);
if (s->c)
{
for (i = 0; i < rows; i++)
{
s->c[i] = malloc(sizeof *(s->c[i]) * columns);
if (s->c[i])
{
// initialize s->c[i][0] through s->c[i][columns-1]
}
}
}
If you want to allocate s->c as a 1D array, then you can define a macro that does the job for you (but you need to know the second dimension):
#define AR(M, X, Y) ((M)[(Y) + dimy * (X)])
I'm surprised nobody mentioned boost::multi_array_ref:
#include <iostream>
#include <boost/multi_array.hpp>
int main()
{
int rows = 4, cols = 3;
// Allocate one big block of contiguous data for entire multi-array
double* arrayData = new double[rows*cols];
if (arrayData)
{
boost::multi_array_ref<double, 2>
arrayRef(arrayData, boost::extents[rows][cols]);
for (int row = 0; row < rows; ++row)
{
for (int col = 0; col < cols; ++col)
{
arrayRef[row][col] = row*cols + col;
std::cout << arrayRef[row][col] << " ";
}
std::cout << std::endl;
}
}
delete [] arrayData;
}
You can also just use boost::multi_array and resize it dynamically:
boost::multi_array_ref<double, 2> marray;
marray.resize(boost::extents[rows][cols]);
精彩评论