Aumentar puntero con malloc contiuamente sin perder lo anterior

shoto_reaper
23 de Abril del 2010
Basicamente lo que quiero hacer es actualizar un puntero continuamente,sin perder los valores almacenados anteriormente.
Este es un ejemplo:

while (strcmp(resp,"si")==0){
conta=0;
clases=(int**)malloc(i*sizeof(int*));
contarray=(int*)malloc(i*sizeof(int));
cout<<"Clase "<<i+1<<endl;
while(alumn!=0){
cout<<"alumno "<<conta+1<<endl;
cin>>alumn;
if(alumn>0){
*clases=(int*)malloc(conta*sizeof(int));
clases[i][conta]=alumn;
conta=conta+1;
}
}



cout<<"desea realizar otra introduccion de clase"<<endl;
cin>>resp;
i=i+1;
}

cout<<"mostrando notas"<<endl;
for(int j=0;j<i;j++){

for(int h=0;h<contarray[j];h++){
cout<<"clases "<<j<<" alumno "<<h<<"="<<clases[j][h];
}
cout<<endl;
}
system("pause");
}



El problema que esta que al cargar las notas,solo esta la ultima guardada,por ejemplo:si solo tengo una clase(i=0) y tres alumnos (conta=2) cuyas notas son 3,5,7,el for me dara numeros sin sentido hasta llegar al clases[0][2],el cual sera 7.

Capitan Kirk
23 de Abril del 2010
Aprecio un par de errores "de bulto".

El primero de ellos es que estás llamando a la función malloc desde dentro de un bucle y sin haber liberado la memoria previamente asignada, con lo cual:
- En cada ejecución del bucle, pierdes la información que pudiera contener la memoria reservada anteriormente, tus punteros apuntarán a otra parte.
- Al asignar nuevamente el puntero, pierdes el bloque de memoria que se había asignado anteriormente (la expresión inglesa es \'memory leak\', podría traducirse como \'goteo de memoria\'). No puedes acceder a él ni puedes liberarlo, puesto que ya no tienes su dirección. Esto, poco a poco, si la ejecución del programa se prolonga en el tiempo y/o se asigna mucha memoria cada vez, puede provocar que el programa deje de funcionar (o algo peor), al no poder suministrar la memoria solicitada. Este error es más común de lo que parece, y no es fácil de depurar, puesto que las consecuencias puede que no aparezcan salvo que se haga una utilización intensiva.

El otro error lo aprecio en el empleo de la variable clases:
La has declarado (por lo que veo en el código que has posteado) como int **, es decir, como \'puntero a puntero a entero\'. Cuando haces el malloc(), lo que obtienes es un array de punteros a enteros, o sea, lases[i] es un puntero a entero. Más adelante, haces

*clases=(int*)malloc(conta*sizeof(int));

clases es un puntero, y tal como lo has hecho, apunta a otro puntero. Cuando haces la asignación anterior, lo único que estás modificando es el lugar al que apunta clases, y volvemos al primer error que he citado.

Resumiendo:

- No utilices malloc dentro de un bucle, a no ser que liberes la memoria dentro del mismo bucle.
- Cuando hagas una reserva de memoria, codifica inmediatamente su liberación, así no se te olvidará.
- Si es posible, libera la memoria reservada en orden inverso a su asignación, esto ayudará a evitar la fragmentación de la memoria libre.

Si necesitas cambiar el tamaño de la memoria reservada, utiliza la función realloc. Ejemplo:

int *ptr; // ptr es un puntero a entero
...
ptr = (int *)malloc(50*sizeof(int)); // Reservas espacio para 50 enteros

Ahora necesito espacio para 25 enteros solamente:

ptr = (int *)realloc(ptr, 25*sizeof(int));

Ahora necesito espacio para 100 enteros:

ptr = (int *)realloc(ptr, 100*sizeof(int));

En el primer caso (disminuyo el tamaño) se respeta el contenido de los primeros 25 elementos, el resto se pierde.

En el segundo caso (partiríamos de 25 elementos), el contenido de lo que ya hay se respeta, el contenido del nuevo espacio está indeterminado.

Para el caso del doble puntero (tu variable clases), tendrías que hacerlo así:

clases = (int **)malloc(n*sizeof(int));

(Esto lo tenías correcto, suponiéndole a i un valor mayor que cero).

y luego, para cada elemento:

clases[0] = (int *)malloc(n1*sizeof(int));
clases[1] = (int *)malloc ... etc ...

o en un bucle for, o while, etc.

Perdona por el rollo. Saludos,