Test Foro de elhacker.net SMF 2.1

Programación => Programación C/C++ => Mensaje iniciado por: Omar_2013 en 11 Marzo 2014, 21:59 PM

Título: Asesoria Memoria Dinamica
Publicado por: Omar_2013 en 11 Marzo 2014, 21:59 PM
Hola, estoy haciendo un programa para contar el numero de palabras que tenga una frase, el problema es que por supuesto siempre el numero de palabras varia, por lo que segun pienso yo, hay que usar memoria dinamica

Código (cpp) [Seleccionar]

int main(int argc, char *argv[])
{
    char Lectura[200], *PTok, **Palabras=NULL;
    int i=0, j=0, ContPal=1;
   
    cin.getline(Lectura, sizeof(Lectura));
   
    PTok=strtok(Lectura," ");
   
    while ( PTok!= NULL )
    {
          AgrEspacio(Palabras, ContPal);//AgrEspacio Agrega Una Fila De Mas A Palabras
          strcpy( Palabras[i], PTok );
          PTok=strtok(NULL," ");
          i+=1;
          ContPal+=1;
    }
   
    for ( j=0; j<i; j++ )
        cout<<Palabras[j]<<endl;
   
    system("PAUSE");
    return EXIT_SUCCESS;
}



El problema como tal es esa funcion para agregar una fila a la matriz, ya que si compila, pero estoy violando el acceso a la memoria en una parte del codigo de esa funcion

Código (cpp) [Seleccionar]

void AgrEspacio ( char **Palabras, int NumPal)
{
     char **TemFilas=new char*[NumPal];
     
     for ( int i=0; i<NumPal; i++ )
     {
         TemFilas[i]=new char[200]; 
         TemFilas[i]=Palabras[i];
     }
         
     Palabras=TemFilas;   
}

La verdad este tema de memoria dinamica se me hace un poco dificil de entender, ya que no se bien cuando es correcto usarla, por ejemplo en este ejercicio podria haber creado una matriz estatica como
Código (cpp) [Seleccionar]
char Palabras[100][200]; en vez de pensar en memoria dinamica, pero la ventaja es que con esta voy agregando filas a mi matriz cuando lo voy necesitando en vez de declarar una estatica y ocupar memoria que tal vez no usare

Gracias por su tiempo.
Título: Re: Asesoria Memoria Dinamica
Publicado por: engel lex en 11 Marzo 2014, 22:20 PM
no es mas facil un
(usando string.h)

char lectura[200];
int i = 0;
int j = 0;
cin >> lectura;
for(i=0;i<strlen(lectura);i++){
  if(lectura[i]==' ')
    j++;
}
cout >> "hay " >> j >> " palabras";


creo que necesita un par de retoques, pero deberia funcionar
Título: Re: Asesoria Memoria Dinamica
Publicado por: Omar_2013 en 11 Marzo 2014, 22:25 PM
Esque la salida del programa deve de ser asi:

Entrada: "Anita Lava La Tina"
Salida: Anita --> 1 vez
           Lava -->  1 vez
           La    -->   1 Vez
           Tina -->  1 Vez
Título: Re: Asesoria Memoria Dinamica
Publicado por: amchacon en 11 Marzo 2014, 22:33 PM
Código (cpp) [Seleccionar]
void AgrEspacio ( char **Palabras, int NumPal)
{
        char **TemFilas=new char*[NumPal];
     
        for ( int i=0; i<NumPal; i++ )
        {
            TemFilas[i]=new char[200]; 
            TemFilas[i]=Palabras[i];
        }
     
        Palabras=TemFilas; 
}


1º Palabras debe pasarse por referencia (&).
2º La igualación TermFilas = Palabras no tiene ningún sentido. Te estas cargando lo que acababas de reservar con new.

Saludos.
Título: Re: Asesoria Memoria Dinamica
Publicado por: Omar_2013 en 11 Marzo 2014, 22:38 PM
Lo que queria hacer al igualar TemFilas[i]=Palabras[i]; era copiar el contenido ya que TemFilas[i] tiene un espacio de mas y esa es la que quiero usar[/size]
Título: Re: Asesoria Memoria Dinamica
Publicado por: amchacon en 11 Marzo 2014, 22:54 PM
No, no haces eso. La función te irá perfectamente así:

Código (cpp) [Seleccionar]
void AgrEspacio ( char **&Palabras, int NumPal)
{
   char **TemFilas=new char*[NumPal];
   
   for ( int i=0; i<NumPal; i++ )
   {
       TemFilas[i]=new char[200];  
   }
   
   Palabras=TemFilas;  
}


Aunque yo eliminaria la variable auxiliar:

Código (cpp) [Seleccionar]
void AgrEspacio ( char **&Palabras, int NumPal)
{
   Palabras =new char*[NumPal];
   
   for ( int i=0; i<NumPal; i++ )
   {
       TemFilas[i]=new char[200];  
   }
}
Título: Re: Asesoria Memoria Dinamica
Publicado por: eferion en 11 Marzo 2014, 22:56 PM
No es necesario usar memoria dinámica... al menos no es necesario que tú te encargues de ello.

Sería más sencillo usando un vector:

Código (cpp) [Seleccionar]

int main(int argc, char *argv[])
{
 char Lectura[200], *PTok;
 vector< string > Palabras;
 int i=0, j=0, ContPal=1;

 cin.getline( Lectura, sizeof( Lectura ) );

 PTok = strtok(Lectura," " );

 while ( PTok != NULL )
 {
    Palabras.push_back( PTok );
    PTok = strtok( NULL, " " );  
 }

 for ( int i=0; i < Palabras.size( ); i++ )
   cout<<Palabras[ i ] << endl;

 system("PAUSE");
 return EXIT_SUCCESS;
}


Está muy bien que aprendas a usar memoria dinámica es un recurso muy potente... pero si la usas acuérdate de liberarla después.

Cita de: Omar_2013 en 11 Marzo 2014, 22:38 PM
Lo que queria hacer al igualar TemFilas[i]=Palabras[i]; era copiar el contenido ya que TemFilas[i] tiene un espacio de mas y esa es la que quiero usar[/size]

Si tu haces TemFilas = Palabras... teniendo en cuenta que ambas variables son punteros... estás haciendo que el puntero TemFilas apunte a Palabras, en otras palabras:

* situación inicial:
   TemFilas = 0xF093 <-- Basura
   Palabras = 0x1234 <-- Dirección apuntada por el puntero
* Con TemFilas = new char[200]; tenemos
   TemFilas = 0x8000 <-- Posición de inicio del array recién reservado
   Palabras = 0x1234 <-- Dirección apuntada por el puntero
* Con TemFilas=Palabras
   TemFilas = 0x1234 <-- Perdiste toda referencia a la posicion 8000 que es donde está el array recién creado
   Palabras = 0x1234 <-- Dirección apuntada por el puntero

¿Qué quiere decir esto? Lo siguiente. Una vez haces TemFilas = Palabras sucede lo siguiente:


strcpy( Palabras[i], "prueba" );
cout << Palabras[i] << "-" << TemFilas[i] << endl; // Imprime: prueba-prueba
TemFilas[i][2] = '#';
cout << Palabras[i] << "-" << TemFilas[i] << endl; // Imprime: pr#eba-pr#eba


Esto es así porque los dos punteros apuntan a la misma cadena y cualquier cambio en la cadena se ve reflejado en los dos punteros.

Título: Re: Asesoria Memoria Dinamica
Publicado por: rir3760 en 12 Marzo 2014, 04:02 AM
Como ya te comento eferion deberías utilizar la biblioteca estándar de C++. Puedes utilizar las clases vector y string para que ellas se encarguen del manejo de memoria y la clase istringstream para obtener las palabras de la linea. Por ejemplo:
Código (cpp) [Seleccionar]
#include <iostream>
using std::cin;
using std::cout;
using std::endl;

#include <string>
using std::string;
using std::getline;

#include <vector>
using std::vector;

#include <sstream>
using std::istringstream;

int main()
{
   cout << "Introduce la linea: ";
   string linea;
   getline(cin, linea);
   
   istringstream is(linea);
   vector<string> palabra;
   string aux;
   while (is >> aux)
      palabra.push_back(aux);
   
   // En C++11 se puede utilizar "auto" para abreviar la declaracion
   for (vector<string>::size_type i = 0; i != palabra.size(); ++i)
      cout << i << ": " << palabra[i] << endl;
   
   return 0;
}


Un saludo