ayuda con problema de matrices y punteros

Iniciado por dato000, 7 Diciembre 2013, 18:10 PM

0 Miembros y 1 Visitante están viendo este tema.

dato000

Que tal gente como estan, estoy retomando el tema de punteros, y estoy en problemas, no he podido hacer el siguiente ejercicio, por favor, echenme una mano, porque no he entendido porque me da errores de segmentation fault, y pues no me imprime la matriz por medio de aritmetica de punteros.

El enunciado del ejercicio es este:

------------------------------------------------------------------------------------------------------------------


En el siguiente código se accede a los elementos de una matriz. Acceder a los mismos elementos con aritmética de apuntadores.


#define N 4
#define M 5
int f, c;
double mt [N][M]
...
for(f=0; f<N; f++)
{
    for(c=0; c<M; c++)
             printf("%1f ", mt[f][c]);
    printf("\n");
}


------------------------------------------------------------------------------------------------------------------

Se que esta en C, pero quise hacer el C++ porque estoy avanzando en todo el tema y quiero pasar rapidamente de punteros, luego memoria dinamica, luego archivos, luego clases y luego hacer cosas en serio.


Código (cpp) [Seleccionar]

#include <iostream>

#define N 4
#define M 5



using namespace std;

int main()
{
   int f, c;
   double mt[N][M];

   double **mt_puntero;

   *(mt_puntero) = &mt[0][0];
   while(*mt_puntero)
   {
       *(*(mt_puntero)) = 2.00;
       mt_puntero++;
   }


   for(f=0; f<N; f++)
   {
       for(c=0; c<M; c++, mt_puntero++)
       {
           //cout << mt[f][c] << " ";
           // Aritmetica de punteros
           cout << *(*(mt_puntero + f) + c) << "--> ";
           cout << &mt_puntero[f][c] << endl;
       }
       cout << endl;
   }

   while(*mt_puntero)
   {
       cout << *(*(mt_puntero ) );
       mt_puntero++;
   }

   return 0;
}


Se que hay varias cosas mal, pero esto es debido a que probe de muchas formas y no he podido dar con el tema, ya he leido varios documentos y no he podido atinarle, agradeceria más allá de que me resuelvan el ejercicio, el que puedan explicarme como es el correcto uso de la aritmetica de punteros enfocado a matrices/arrays multidimensionales

slds



rir3760

Cita de: dato000 en  7 Diciembre 2013, 18:10 PMEl enunciado del ejercicio es este:
Supongo algo salio mal en tu mensaje ya que no esta el enunciado del programa.

Cita de: dato000 en  7 Diciembre 2013, 18:10 PM
printf("%1f ", mt[f][c]);
Esta mal. "%lf" se utiliza con scanf para leer un valor de tipo double, en el caso de printf "%f" es para el tipo double y "%Lf" para el tipo long double.

El primer error en tu segundo programa (C++) se encuentra en la sentencia:
Código (cpp) [Seleccionar]
*(mt_puntero) = &mt[0][0];
La variable "mt_puntero" es un puntero y antes de cualquier uso (por ejemplo indirección) debes almacenar en el una dirección valida.

Otro detalle algo feo: cuando se nombra un array en la mayoría de las ocasiones resulta en la dirección en memoria de su primer elemento, por ejemplo un array de enteros genera un puntero a entero y un array de arrays (tu caso) genera un puntero a array. Por ello el tipo del puntero debe ser "double (*)[M]"

Otro error es utilizar dos bucles como este:
Código (cpp) [Seleccionar]
while (*mt_puntero) ...
Ello funciona con cadenas "a la C" porque estas tienen un valor que indica el final de estas (el '\0') pero en tu caso tal delimitador no existe. En su lugar debes utilizar aritmética de punteros, por ejemplo:
Código (cpp) [Seleccionar]
while (mt_puntero < mt + N) ...

El programa con (algunos de) los cambios:
Código (cpp) [Seleccionar]
#include <iostream>
using namespace std;

#define N 4
#define M 5

int main()
{
   int f, c;
   double mt[N][M];
   
   double (*p_array)[M];
   double *p_double;
   
   for (p_array = mt; p_array < mt + N; p_array++)
      for (p_double = *p_array; p_double < *p_array + M; p_double++)
         *(p_double) = 2.00;
   
   p_array = mt;
   for (f = 0; f < N; f++){
      for (c = 0; c < M; c++){
         cout << *(*(p_array + f) + c) << "--> ";
         cout << &p_array[f][c] << endl;
      }
      cout << endl;
   }
   
   // ...

   return 0;
}


Un saludo
C retains the basic philosophy that programmers know what they are doing; it only requires that they state their intentions explicitly.
--
Kernighan & Ritchie, The C programming language

dato000

Vaya, bueno ya deje arreglado el enunciado, la parte C era el del ejercicio que queria convertir en C++, efectivamente solo encontre ejemplos con "Cadenas a la C", no cai en cuenta de lo del delimitador "\0" tienes toda la razón.

Funciona perfectamente pero tengo unas dudas, ayudame a aclararlas maese:

Código (cpp) [Seleccionar]

double (*p_array)[M];
double *p_double;


Que significa particularmente el (*p_array)[M], hay que indireccionar por separado las columnas y las filas???


Código (cpp) [Seleccionar]

for (p_array = mt; p_array < mt + N; p_array++)
{
        for (p_double = *p_array; p_double < *p_array + M; p_double++)
        {
            *(p_double) = 2.00;
        }
}

p_array = mt;


Entiendo entiendo entiendo, dime entonces, o confirmame, siempre es necesario indicar al puntero que retorne a la posición inicial de la matriz, eso es lo que provoca el error de "segmentation fault", es así cierto??

Que significaria entonces si se hace esto:

Código (cpp) [Seleccionar]

**(p_double) = 2.00;
*(*(p_double) = 2.00;





rir3760

Cita de: dato000 en  7 Diciembre 2013, 19:20 PM
Código (cpp) [Seleccionar]
double (*p_array)[M];
double *p_double;


Que significa particularmente el (*p_array)[M], hay que indireccionar por separado las columnas y las filas?
Por partes.

Tienes un array de arrays de doubles (el array mt) y la intención es practicar con los punteros y la aritmética con estos. Para procesar un array de tipo "T [N]" se debe utilizar un puntero de tipo "T *". En este caso:
1) El array es mt y el tipo de sus elementos es "double [M]"
2) El puntero para procesar cada elemento debe ser de tipo "double (*)[M]", se utilizan paréntesis porque de no hacerlo (utilizando "double *[M]") la declaración se tomaría como la de un array de M elementos de tipo "double *", en otras palabras no seria un puntero a array sino un array de punteros (no es lo mismo y no es igual).

Con el puntero "p_array" procesamos cada uno de los elementos del array mt (mt[ 0 ], mt[ 1 ], etc.), como este es un array de arrays cada elemento también es un array y ahí utilizamos el puntero "p_double" para procesar los elementos:
Código (cpp) [Seleccionar]
// Por cada elemento del array mt (mt[0], mt[1], ...)
for (p_array = mt; p_array < mt + N; p_array++){
   // Por cada elemento del array mt[i] (mt[i][0], mt[i][1], ...)
   for (p_double = *p_array; p_double < *p_array + M; p_double++){
      *(p_double) = 2.00;
   }
}


Cita de: dato000 en  7 Diciembre 2013, 19:20 PM
Que significaria entonces si se hace esto:

Código (cpp) [Seleccionar]
**(p_double) = 2.00;
*(*(p_double) = 2.00;

No es valido ya que el tipo de "p_double" es "double *", al aplicar el operador de indirección con "*(p_double)" (los paréntesis no son necesarios en este caso) ya no tratas con el puntero sino con el objeto apuntado y no puedes hacer, siguiendo el ejemplo, "*(2.00)".

Un saludo
C retains the basic philosophy that programmers know what they are doing; it only requires that they state their intentions explicitly.
--
Kernighan & Ritchie, The C programming language

dato000

wow, un poco complicado pero entiendo la mayoria de cosas que decias, muchas gracias, muy bueno en serio, tendre que practicar más (y lo estoy haciendo) todo este cuento.