2010-01-29 6 views
6

Tengo este bucle que da seg. culpa.¿Cómo trato un puntero como una matriz múltiple?

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); 

    } 
    } 

Dentro s-> c es:

double* c; 

Cuando ejecuta sólo da salida:

d 27.000000 
m 0 
n 0 

y luego seg. culpa.

Funcionó cuando traté el s-> c como una matriz 1D, pero realmente me gustaría tratarlo como una matriz 2D.

¿Es posible, cuando el puntero c está en una estructura?

Si es así, ¿es (&s->c)[m][n] la forma correcta de acceder a los elementos?

Sandra

+2

¿Puede darnos un poco más de código especialmente de la asignación? – tur1ng

+0

¿Cómo se asigna c? – 3lectrologos

+0

Ahora se agrega cómo se asigna c. –

Respuesta

5

El problema es que el compilador no conoce las dimensiones de su matriz.

Cuando se tiene: double tab[m][n] se puede acceder al elemento de tab[row][col] como *(tab + (row * n) + col)

En el caso de que sólo tiene double *tab; que puede ser considerado como el puntero al elemento tab[0][0] sin información sobre las dimensiones de la matriz y el compilador puede no calcule la dirección correcta.

Puede calcular la dirección usted mismo (por ejemplo, usando una macro) pero perderá la buena sintaxis tab[x][y].

Me sorprende que compile. Debería haber recibido al menos una advertencia acerca de lanzar implícitamente un doble a un puntero.

0

Si desea asignar s-> c como una matriz 1D, a continuación, se puede definir una macro que hace el trabajo para usted (pero lo que necesita saber la segunda dimensión):

#define AR(M, X, Y) ((M)[(Y) + dimy * (X)]) 
+4

Pero en esta era C++, tratamos de usar funciones (en línea) en lugar de macro. – xtofl

+0

Simplemente no quería tener que pasar la dimensión como parámetro también (para que la macro se parezca a la expresión c [m] [n]). – 3lectrologos

4

Estoy muy sorprendido de que incluso compila. Aparentemente c es un double*, entonces (&s->c)[m] es el m'th double. Ahora, double no tiene un operator[], así que no veo cómo la parte [n] en (&s->c)[m][n] puede ser legal.

Presumiblemente, usted ha declarado c de manera diferente. Hay diferentes soluciones: un puntero a un puntero, un puntero a una matriz de dobles, una matriz de punteros a dobles, etcétera. Todo podría funcionar, si las asignaciones coinciden con la declaración. En su caso, la asignación no coincidirá con la declaración.

+3

Creo que 's-> c' es un' double * ', entonces' & s-> c' es un 'double **', pero '(& s-> c) [1]' será basura, así '(& s-> c) [1] [0] 'activa la falla. – dave4420

+0

¿Cómo se vería un "puntero a una matriz de dobles"? –

+0

double * values ​​[]; – tur1ng

2

La forma correcta para acceder a los elementos de la matriz es

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

es eso lo que quieres decir, tratándolo como una matriz 1D?

+0

Sí, cuando lo hago así, funciona. Pero no entiendo por qué falla, cuando lo trato como una matriz 2D. –

+0

Porque la subscripción de matriz se define en términos de aritmética de puntero. Para su código, esto significa que '(s-> c) [m] [n]' se evalúa como '* (* (s-> c + m) + n)'. Esto significa que '* (s-> c + m)' se espera que se evalúe como un tipo * puntero *. Sin embargo, dado que 's-> c' es tipo' double * ',' * (s-> c + m) 'evalúa a un valor doble. Intentar tratar este valor doble como un puntero es lo que conduce a la falla seg. –

1

acceder a los elementos utilizando

Tal vez a través de una función en línea, para evitar un comportamiento inesperado.

El compilador no conoce el ancho de su matriz 2D deseada. Posiblemente podría interpretar (& s-> c) [m] [n] como s-> c [m + n], o como algo bastante diferente.

1

Respuesta breve: no se puede tratar como una matriz 2D, al menos no de la manera esperada.

La razón por la escritura

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

no funciona puede demostrar de la siguiente manera. Suponga que la dirección de s->c es 0x00080004, y la dirección de la memoria asignada dinámicamente apuntada por s->c es 0x00001000.

  1. La expresión (&s->c)[m][n] se evalúa como *(*(&s->c + m) + n);
  2. La expresión &s->c evalúa a 0x00080004;
  3. La expresión (&s->c + m) evalúa a 0x00080004+m;
  4. La expresión *(&s->c + m) evalúa el valor de lo que apunta el 0x00080004+m. Si m es 0, entonces 0x00080004+m apunta a 0x00001000, que es la dirección de su memoria asignada dinámicamente (*(&x) == x). Si m tiene algún otro valor, entonces 0x00080004+m señala en algún lugar al azar;
  5. La expresión (*(&s->c + m) + n) se evalúa como 0x00080004+m puntos para compensar por n. Si m es 0, entonces el valor es 0x00001000+n, o un desplazamiento en su memoria asignada dinámicamente. Si m no es 0, entonces el valor es algo aleatorio;
  6. La expresión *(*(&s->c) + m) + n) intenta desreferenciar el valor anterior. Si m es 0, entonces el resultado es el valor de un elemento en la matriz asignada dinámicamente. Si m no es 0, entonces el resultado es ... algo más. En tu caso, un segfault.

Si desea asignar dinámicamente una matriz 2D, usted tiene que utilizar un puntero a un puntero y asignarlo en los pasos, así:

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] 
    } 
    } 
} 
0

me sorprende que nadie ha mencionado 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; 
} 

Usted también puede utilizar impulso :: multi_array y cambiar su tamaño de forma dinámica:

boost::multi_array_ref<double, 2> marray; 
marray.resize(boost::extents[rows][cols]); 
Cuestiones relacionadas