How to handle a pointer like multiple arrays?

I have this loop that gives seg. malfunction.

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 there is:

 double* c; 

When executed, it simply outputs:

 d 27.000000 m 0 n 0 

and then seg. malfunction.

This worked when I saw s-> c as a 1D array, but I would really like to treat it as a 2D array.

Is it possible when the c-pointer is in the structure?

If so, this is (&s->c)[m][n] , then the correct way to access elements?

Sandra

+6
c ++ c
source share
7 answers

The problem is that the compiler does not know the size of your matrix.

If you have: double tab[m][n] , you can access the tab[row][col] element as *(tab + (row * n) + col)

In your case, you only have double *tab; , which can be considered as a pointer to the element tab[0][0] without information about the size of the matrix, and the compiler cannot calculate the correct address.

You can figure out the address yourself (for example, using a macro), but you will lose the pretty syntax tab[x][y] .

I am surprised that it compiles. You should have received at least a warning about the implicit cast of the double to the pointer.

+5
source share

I am very surprised that it even compiles. Apparently, c is double* , so (&s->c)[m] is m'th double . Now double does not have operator[] , so I don’t see how the [n] part in (&s->c)[m][n] can be legal.

Supposedly you declared c differently. There are various solutions: a pointer to a pointer, a pointer to an array of doubles, an array of pointers to pairs, etc. Everything can work if the distributions match the ad. In your case, the distribution will not match the ad.

+4
source share

The correct way to access array elements is

 d = s->c[m * width + n]; 

Is that what you mean by treating it as a 1D array?

+2
source share

Access items using

 double d = s->c[m*width+n]; 

Perhaps using a built-in function to avoid unexpected behavior.

The compiler does not know the width of your intended 2D array. Perhaps he interprets (& s-> c) [m] [n] as s-> c [m + n] or as something completely different.

+1
source share

Short answer: you cannot think of it as a 2D array, at least not in the way you expect.

Reason for writing

 (&s->c)[m][n] 

does not work, you can show the following. Assume that the address 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 to 0x00080004 ;
  • The expression (&s->c + m) is evaluated as 0x00080004+m ;
  • The expression *(&s->c + m) evaluates the value of what 0x00080004+m points to. 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 indicates somewhere random;
  • The expression (*(&s->c + m) + n) means that 0x00080004+m indicates an offset by n . If m is 0, then the value is 0x00001000+n or the offset in your dynamically allocated memory. If m not equal to 0, then the value is something random;
  • The expression *(*(&s->c) + m) + n) tries to dereference the above value. If m is 0, then the result is the value of the element in the dynamically allocated array. If m not 0, then the result will be ... something else. In your case, segfault.

If you want to dynamically select a 2D array, you need to use a pointer to a pointer and select it in steps, for example:

 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] } } } 
+1
source share

If you want to select s-> c as a 1D array, 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)]) 
0
source share

I am surprised that no one 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 dynamically resize it:

 boost::multi_array_ref<double, 2> marray; marray.resize(boost::extents[rows][cols]); 
0
source share

All Articles