开发者

How do I treat a pointer as a multi array?

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.

  1. The expression (&s->c)[m][n] is evaluated as *(*(&s->c + m) + n);
  2. The expression &s->c evaluates to 0x00080004;
  3. The expression (&s->c + m) evaluates to 0x00080004+m;
  4. The expression *(&s->c + m) evaluates to the value of whatever is pointed to by 0x00080004+m. If m is 0, then 0x00080004+m points to 0x00001000, which is the address of your dynamically allocated memory (*(&x) == x). If m is any other value, then 0x00080004+m points somewhere random;
  5. The expression (*(&s->c + m) + n) evaluates to whatever 0x00080004+m points to offset by n. If m is 0, then the value is 0x00001000+n, or an offset into your dynamically allocated memory. If m is not 0, then the value is something random;
  6. The expression *(*(&s->c) + m) + n) attempts to dereference the above value. If m is 0, then the result is the value of an element in the dynamically allocated array. If m 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]);
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜