elhacker.net cabecera Bienvenido(a), Visitante. Por favor Ingresar o Registrarse
¿Perdiste tu email de activación?.

 

 


Tema destacado: Introducción a Git (Primera Parte)


+  Foro de elhacker.net
|-+  Programación
| |-+  Programación C/C++ (Moderadores: Eternal Idol, Littlehorse, K-YreX)
| | |-+  C++ Memoria dinámica
0 Usuarios y 1 Visitante están viendo este tema.
Páginas: [1] Ir Abajo Respuesta Imprimir
Autor Tema: C++ Memoria dinámica  (Leído 2,478 veces)
rafaelfinacut10

Desconectado Desconectado

Mensajes: 3


Ver Perfil
C++ Memoria dinámica
« en: 4 Febrero 2018, 08:28 am »


Hola a todos...Necesito ayuda para terminar un código, pero no encuentro la manera de hacerlo...es un programa que opera en la colección dinámica de datos. La idea es usar una estructura que contenga dos campos: la primera almacena el número de elementos en las colecciones, y la segunda es la colección real (un vector de ints dinámicamente asignado). Como puede ver, la colección está llena con la cantidad requerida de datos pseudoaleatorios. La función principal no esta terminada.. Esto es lo que se espera
1.Si la colección está vacía, debe asignar un vector de un elemento y almacenar un nuevo valor en él
2. Si la colección no está vacía, debe asignar un nuevo vector con una longitud mayor en uno que el vector actual, luego copiar todos los elementos del antiguo vector al nuevo, agregar un nuevo valor al nuevo vector y finalmente liberar el vector viejo.

Código
  1. #include <iostream>
  2. #include <cstdlib>
  3. #include <ctime>
  4. using namespace std;
  5. struct Collection {
  6. int  elno; int *elements;
  7. };
  8.  
  9. void AddToCollection(Collection &col, int element) {
  10. // la primera parte de la funcion
  11. if (col.elno==0){
  12.   col.elements= new int[1];
  13.   col.elements[0]= element;
  14. }
  15. //lo que no esta terminado
  16.   else {
  17.   int *temporal;
  18.   temporal = new[];
  19. }
  20.  
  21. }
  22. void PrintCollection(Collection col) {
  23. cout << "[ "; for(int i = 0; i < col.elno; i++)  
  24. cout << col.elements[i] << " "; cout << "]" << endl; }
  25.  
  26. int main(void) {
  27. Collection collection = { 0, NULL };
  28. int elems; cout << "How many elements? ";
  29. cin >> elems;
  30. srand(time(NULL));
  31. for(int i = 0; i < elems; i++)  
  32. AddToCollection(collection, rand() % 100 + 1); PrintCollection(collection); delete[] collection.elements;
  33. return 0;
  34. }


En línea

MAFUS


Desconectado Desconectado

Mensajes: 1.603



Ver Perfil
Re: C++ Memoria dinámica
« Respuesta #1 en: 5 Febrero 2018, 18:06 pm »

Deberías dar un poco de formato a tu código: cada sentencia en una línea, controlar las sangrías, dejar las llaves de cierre solas en su propia línea. Consideraciones estéticas. El código se ve mucho mejor y a simple vista se puede seguir de forma más intuitiva.

A lo que voy. Te dejo la función inacabada rellena con el código comentado más una recomendación: cuanto menos código escribas mejor (sin llegar a hacer críptica la solución, hay que sacrificar muchas veces la simplicidad por la claridad). La lógica muchas veces se puede simplificar, y no digo solo operaciones lógicas sino las líneas de código. Muchas veces el código se repite y no nos damos cuenta. Vale la pena perder un poco de tiempo en revisarlo y dejar todo lo que se repita fuera de las estructuras condicionales y reorganizar éstas para que solo toquen los pequeños cambios que se suceden.

Tu solución, supongo que esto te lo ha dado el profesor
Código
  1. void AddToCollection(Collection &col, int element) {
  2.    // la primera parte de la funcion
  3.    if (col.elno==0) {
  4.        col.elements = new int[1];
  5.        col.elements[0] = element;
  6.    }
  7.    //lo que no esta terminado
  8.    else {
  9.        int *temporal;
  10.        int i;
  11.  
  12.        temporal = new int[col.elno + 1]; // Hago que temporal sea un elemento más grande que el actual número de elementos.
  13.        for(i = 0; i < col.elno; ++i)
  14.            temporal[i] = col.elements[i]; // Copio todos los elementos del array antiguo al nuevo.
  15.        temporal[i] = element; // i está actualizada al nuevo último elemento por la forma en que trabaja for,
  16.                               // así que guardo el elemento pasado a la función.
  17.        delete[] col.elements; // Ahora puedo borrar el arrar antiguo
  18.        col.elements = temporal; // y hacer que el puntero elements apunte al nuevo array.
  19.    }
  20.    col.elno++; // Actualizo elno para indicar que hay un elemento más.
  21. }

Ahora la mía:
Se basa en que todo el trabajo es el mismo, menos en una cosa, tanto si no había elementos guardados o si los había.
Obviamente faltan las comprobaciones de seguridad, por si acaso hubiera algún fallo pero no están incluidas por simplicidad y claridad.

Código
  1. void AddToCollection(Collection &col, int element) {
  2.    int *temporal;
  3.    int i;
  4.  
  5.    temporal = new int[col.elno + 1];
  6.    for(i = 0; i < col.elno; ++i)
  7.        temporal[i] = col.elements[i];
  8.    temporal[i] = element;
  9.    if(col.elno) // Esta es la excepeción que he nombrado. Que es lo mismo a: if(col.elno > 0)
  10.        delete[] col.elements;
  11.    col.elements = temporal;
  12.    col.elno++;
  13. }


« Última modificación: 5 Febrero 2018, 18:16 pm por MAFUS » En línea

dijsktra

Desconectado Desconectado

Mensajes: 110


Mr Edsger Dijsktra (Tribute to)


Ver Perfil
Re: C++ Memoria dinámica
« Respuesta #2 en: 12 Febrero 2018, 16:18 pm »

Comentando un poco el problema original

[...] es un programa que opera en la colección dinámica de datos.
[...]
Esto es lo que se espera
1.Si la colección está vacía, debe asignar un vector de un elemento y almacenar un nuevo valor en él
2. Si la colección no está vacía, debe asignar un nuevo vector con una longitud mayor en uno que el vector actual, luego copiar todos los elementos del antiguo vector al nuevo, agregar un nuevo valor al nuevo vector y finalmente liberar el vector viejo.

Le veo un fallo a este planteamiento. Está claro que la mayor ventaja de emplear dinámica es que se ajusta más la memoria seǵun la necesidad en tiempo de ejecución... Pero se incurre en gran ineficiencia en cuanto a tiempo...
Me explico:

Añadir el primer elemento cuesta 1, el segundo 2, el tercero 3, el cuarto 4... debido a que tienes que hacer una copia del array aumentado a cada momento... De esta manera incurres en coste cuadratico O(n^2), cuando, con memoria estatica, aunque ineficaz en espacio,  tenias un coste  O(n) en tiempo

Código:
1+2+3 + ... + n = n(n+1)/2  \in O(n^2) 

lo que hace muy costoso e ineficiente...

Este es un viejo problema de coste amortizado...

Básicamente consiste en, cada vez que se incremente en la memoria, hacerlo multiplicando por un factor - que depende de una heurística o de la aplicación particular...

En nuestro caso, elegimos FACTOR=2, por lo que cada vez que se "llene la memoria" la duplicamos, y solo en ese momento, hacemos copia del vector original . Es cierto que se pierde precisión con respecto  a la idea dinamica original de tu planteamiento llegando a gastar N*2 cuando sólo se tiene N+1 en el caso peor, pero en términos de coste amortizado en tiempo es de coste constante O(1)...  (es algo complejo de explicar en un solo post)


Primero vamos con la entrada (1 renglon) y salida (2 y 3 renglon) de los programas. El programa almacena la colección de entrada en un array estatico de como mucho 1000 elementos y despues lo convierte a colección dinámica. Se puede ver el ratio de memoria empleada/reservada
 
Código:
1
1
N/MAX=1/10000 vs. N/NN=1/1

Código:
1 2
1 2
N/MAX=2/10000 vs. N/NN=2/2


Código:
1 2 3 4
1 2 3 4
N/MAX=4/10000 vs. N/NN=4/4

Código:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
N/MAX=16/10000 vs. N/NN=16/16


Código:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
N/MAX=32/10000 vs. N/NN=32/32

Ahora el codigo del programa.
Yo voy a lo sustancial, no manejo "structs" , pero es posible que a tí te interese para simular un TAD, y lo podrás adoptar a tu manera con "structs". Tampco programo la reservar memoria, porque viene con

Código
  1. #include <stdlib.h>
  2. void *realloc(void *ptr, size_t size);
  3.  

pero a ti te puede interesar programarla "por razones didácticas"

Este es el programa

Código
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3.  
  4. #define MAX 10000
  5.  
  6. #define FACTOR 2
  7.  
  8. /* Pre : *NN = 1  */
  9. void static2Dynamic(const int V[],const int N,int **D, int *NN)
  10. {
  11.  int nn,n;
  12.  
  13.   /* I : nn <= *NN  */
  14.  for ( nn=n=0; n<N; n++)
  15.    {
  16.      if (nn == *NN)
  17.       {
  18.          (*NN) *= FACTOR;
  19.  if  (!(*D=(int *)realloc(*D,sizeof(int)*(*NN))))
  20.          {
  21.            perror("realloc");
  22.            exit(EXIT_FAILURE);
  23.          }
  24.       }
  25.      (*D)[nn++]= V[n];
  26.    }
  27. }
  28.  
  29. int main (int argc, char **args)
  30. {
  31.  int *D ;
  32.  int N,n,NN;
  33.  int V[MAX];
  34.  if  (!(D=(int *)malloc(sizeof(int))))
  35.    {
  36.      perror("malloc");
  37.      exit(EXIT_FAILURE);
  38.    }
  39.  NN=1;
  40.  for(N=0; (scanf("%d",&V[N])!=EOF); N++);
  41.  static2Dynamic(V,N,&D,&NN);
  42.  for( n=0; n<N; n++) printf("%d ",D[n]);
  43.  printf("\nN/MAX=%d/%d vs. N/NN=%d/%d\n",N,MAX,N,NN);
  44.  return 0;
  45. }
  46.  
  47.  
  48.  

Ahora bien, fijate lo que psa si metemos, digamos 33 elementos...
Código:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
N/MAX=33/10000 vs. N/NN=33/64

Se despercia casi la mitad, pero aún así, no tanto como 33/10000...

Por ultimo, si quieres progrmaarte tu realloc, puede ser algo así

Código
  1. void *myrealloc(const int *ptr, const size_t old_size,const size_t new_size )
  2. {
  3.  int *p;
  4.  if (!(p = malloc(new_size)))
  5.    {
  6.      perror("malloc");
  7.      exit(EXIT_FAILURE);      
  8.    }
  9.  int i;
  10.  for (i=0; (i < old_size) && (i < new_size);i++) *(p+i) = *(ptr+i);
  11.  free((void *)ptr);
  12.  return p;
  13. }
  14.  

Cambiando lo que haya que cambiar en el fuente del main
« Última modificación: 14 Febrero 2018, 08:57 am por dijsktra » En línea

Si la depuración es el proceso de eliminar fallos en el software, entonces programar debe ser el proceso de ponerlos dentro. (Edsger Dijsktra)
Páginas: [1] Ir Arriba Respuesta Imprimir 

Ir a:  

Mensajes similares
Asunto Iniciado por Respuestas Vistas Último mensaje
Memoria dinámica
Programación C/C++
eleon 6 4,802 Último mensaje 24 Enero 2012, 22:17 pm
por Eternal Idol
Memoria dinamica? « 1 2 »
Programación C/C++
vangodp 11 5,271 Último mensaje 30 Abril 2014, 12:35 pm
por vangodp
Memoría dinámica
Programación C/C++
Developer Diego 4 2,444 Último mensaje 20 Mayo 2014, 23:10 pm
por Developer Diego
Problemas de perdida de memoria con memoria dinamica
Programación C/C++
ing_maipu 1 2,111 Último mensaje 28 Octubre 2017, 18:48 pm
por CalgaryCorpus
Uso de referencias con memoria dinámica [C++]
Programación C/C++
K-YreX 6 2,374 Último mensaje 1 Abril 2019, 02:40 am
por Loretz
WAP2 - Aviso Legal - Powered by SMF 1.1.21 | SMF © 2006-2008, Simple Machines