[C con Clase] Duda con el uso Memoria Dinamica

Steven Davidson steven en conclase.net
Vie Feb 16 19:43:56 CET 2007


Hola Lucas,

El pasado 2007-02-16 18:01:37, Lucas escribió:

L> Hola a todos les escribo en esta oportunidad para consultarles:
L> Tengo el siguiente codigo

Veamos el código fuente. Te voy comentando a medida que vayamos viendo el programa.

L> en el archivo "main.cpp"
L> #include <cstdlib>
L> #include <iostream>
L> #include "Maps.h"
L> using namespace std;
L> int main(int argc, char *argv[])
L> {
L>     cout << "\nCrando Mapa...";     //creando el mapa
L>     clMap MapaA(30,30);
L>     cout << "\nReservando Memoria...";
L>     MapaA.SetDimenciones(19,38);
L>     cout << "\nMapa Creado con Exito.";
L>     cin.get();
L>     return EXIT_SUCCESS;
L> }
L> Y en el archivo "maps.h"
L> class clMap
L> {
L>     private:
L>         int clDimX;
L>         int clDimY;
L>         int **clDimMap;
L>     public:
L>         clMap(int ctDimX, int ctDimY);
L>         ~clMap();
L>         void SetDimenciones (int ctDimX, int ctDimY);
L>         int SetCharPos (int ctPosX, int ctPosY);
L> };
L> clMap::clMap(int ctDimX, int ctDimY)
L> {
L>     clDimX = ctDimX;
L>     clDimY = ctDimY;
L> }

Tienes un error con el constructor. No diste un valor determinado al puntero 'clDimMap', por lo que éste contiene basura.

Sugiero usar la lista inicializadora del constructor. Esto es,

clMap::clMap( int ctDimX, int ctDimY )
: clDimX(ctDimX), clDimY(ctDimY), clDimMap(0)  {}

Usar la lista inicializadora suele ser más rápido. Además, con esta lista dejamos claro los valores iniciales de los datos miembros antes si quiera de realizar cualesquier sentencias en el cuerpo del constructor. En este caso, no necesitamos hacer nada más en el cuerpo, aunque podríamos incluir algunas sentencias para comprobar la validez de los valores de las dimensiones. Imagínate que se instancia un objeto con "dimensiones" negativos o incluso 0 (cero).

L> void clMap::SetDimenciones(int ctDimX, int ctDimY)
L> {
L>     delete clDimMap;

Antes tenías dos errores, pero al arreglar el problema con el constructor, sólo nos queda un error.

Intentas borrar el mapa previamente creado. Sin embargo, esto no es correcto. De hecho, deberías hacer lo mismo que en tu destructor. Tienes que ir liberando la memoria de cada "fila" y luego la del array de punteros. Sugiero crear una función miembro que haga esta tarea: borrar completamente la memoria de la tabla.

L>     clDimX = ctDimX;
L>     clDimY = ctDimY;
L>    
L>     clDimMap = new int*[ctDimX];
L>     for (int i=0; i < ctDimX; i++)
L>     {
L>     clDimMap[i] = new int[ctDimY];
L>     }
L>    
L>     for (int i = 0; i < ctDimX; i++)
L>     {
L>         for (int j = 0; j < ctDimY; i++)
L>         {
L>             clDimMap[i][j] = 0;
L>         }
L>     }

Podrías optimizar un poco este algoritmo para reducir la cantidad de bucles. Cada vez que crees una nueva fila, entonces aprovecha para darle valores iniciales. Como estás asignando 0 (cero) a todos los elementos, sugiero invocar 'memset()' que se declara en <cstring>. Por ejemplo,

for( int i=0; i < ctDimX; i++ )
{
  clDimMap[i] = new int[ctDimY];
  memset( clDimMap[i], 0, sizeof(int)*ctDimY );  // Escribir ceros
}

L> }
L> clMap::~clMap()
L> {
L>     for (int i; i < clDimX; i++)

Aquí tienes un error. Tienes que inicializar 'i' a 0 (cero). Esto es,

for(int i=0; i < clDimX; i++ )

L>     {
L>         delete[] clDimMap[i];
L>     }
L>     delete[] clDimMap;
L> }

Como he sugiero antes, podrías usar esa función miembro para liberar la memoria de la tabla e invocarla aquí.

L> int SetCharPos (int ctPosX, int ctPosY)
L> {
L> }
L> cuando Compilo esta todo barbaro, a la hora de que ejecuta la Funcion 
L> "SetDimenciones" reserva la memoria con exito, pero cuando quiero 
L> escribirla, me tira un error
L> La instruccion en "0x00401469" hace referencia a la memoria en 
L> "0x0000000". la memoria no se puede "written".
L> debo suponer que es por que quiero acceder a un lugar que "no reserve".
L> Alguna sugerencia?? ven algun error en el codigo (sobre todo en la calse)??

Exacto. Esto tiene que ver con no haber inicializado el puntero 'clDimMap'. Al contener basura, seguramente apunta a una dirección de memoria que no es tuya. Cuando ejecutas la sentencia de borrar esa memoria, el sistema operativo se entromete para prevenir problemas de corrupción.


Espero que esto te sirva.

Steven


Más información sobre la lista de distribución Cconclase