Documentos de Académico
Documentos de Profesional
Documentos de Cultura
Laboratorios de computación
salas A y B
M.I Edgar Tista García
Profesor:
01
Grupo:
04
No de Práctica(s):
24
No. de Lista o Brigada:
2022-2
Semestre:
Fecha de entrega:
Observaciones:
CALIFICACIÓN: __________
Objetivos
Objetivo general:
Objetivo de la clase:
Para este caso, en particular, lo que hace el programa es seguir los tres pasos de
los apuntadores.
Por último, el paso 3: usar del apuntador. En este caso, lo que se hará es
imprimir los valores del apuntador con un ciclo for (línea 14 y 15), los cuales
previamente se asignaron con un scanf en la línea 9 y 10, pero no se les da
ningún valor, solamente es para indicar el número de huecos reservados.
Ya para finalizar el análisis, tenemos que remontarnos a la línea 19. En esta parte
del código, vemos que se hace uso de la función free. Esta función aparece cuando
se ha terminado de utilizar el bloque de memoria o la memoria dinámica, asignada
por malloc( ).Su objetivo es el de liberar el espacio de memoria y dejarlo para otros
usos, es por eso que en la salida del programa nos aparece en pantalla un mensaje
indicándonos que se ha liberado el espacio.
Una vez analizado y compilado el programa, la salida que nos muestra en pantalla
es la siguiente:
Tras codificar y ejecutar el código dado, la salida en pantalla que nos muestra es la
siguiente:
Como podemos ver, el primer parámetro esta dado por la variable num, la cual
guardará el número de elementos que el usuario dará e indica las localidades a
reservar. En el segundo parámetro, se hace uso de sizeof, el cual nos dará el
tamaño en bytes del dato al que se le asigna el apuntador y que así el tamaño de
cada elemento sea el correcto.
Otra cosa importante que hay que indicar, es que la función calloc limpia la memoria
asignando ceros como valores iniciales en las localidades de memoria reservada,
siendo esta la razón de que, en la salida, se nos muestra el vector con valores de
0, no como en malloc, que muestra basura.
De ahí en fuera, el programa sigue el mismo codificado que el ejercicio anterior, usa
una condición if, para que entre al ciclo for que imprimirá los elementos del vector y
al finalizarlo, se hará uso de la función free. La cual hay que remarcar su importancia
en cada programa con uso de memoria dinámica, pues al ya no utilizarla, se debe
de liberar.
En este ultimo ejercicio, se nos ejemplifica la función realloc para el uso de memoria
dinámica, siendo el más completo y demostrativo. Compilando y ejecutando el
programa, se nos muestra la siguiente salida en pantalla:
Este programa, al inicio implementa la función malloc. Nos pide el tamaño de los
elementos a reservar y después realiza la asignación al apuntador void. Cabe
resaltar que, en este ejemplo, se declaran dos apuntadores, uno será para la
primera parte del programa, la cual hace uso de malloc y la segunda será para la
implementación de realloc y el aumento del tamaño del conjunto de elementos.
Una vez pasado esto, para el aumento del tamaño del conjunto, se aplica la función
realloc, pero antes de esto, como el tamaño del conjunto será aumentado al noble,
en la línea 23, lo que se hace es solamente multiplicarlo por dos.
Donde vemos, que realloc seguirá devolviendo un apuntador de tipo void y recibí
dos parámetros: el apuntador previamente declarado, ya sea por malloc o calloc, y
el nuevo tamaño, en bytes, que se desea redimensionar al conjunto.
Para este caso en particular, vemos que se hace uso del segundo apuntador, lo cual
es importante mencionar que no se puede usar un mismo apuntador para
aumentarlo, lo correcto es declarar un segundo apuntador y usar la función realloc
en este.
Ya como paso final, el programa imprime los datos usando el ciclo for para recorrer
desde el primer elemento hasta el último, del nuevo apuntador. Como sabemos, el
programa debe terminar con la función free, para liberar la memoria usada y evitar
posibles errores. En este caso vemos que el apuntador que está liberando es
arreglo, el primer apuntador reservado por malloc y no realloc; esto se realiza de
esta manera, ya que previamente en la línea 26, se asignó a arreglo el segundo
apuntador - arreglo2 -. Por lo tanto, una vez aclarado esto, damos por finalizado el
ejercicio 3.
Desarrollo de la practica:
Ejercicio 1.
Tras compilar y ejecutar el código dado, la salida que se nos muestra en pantalla es
la siguiente:
Como podemos ver, lo primero que se nos imprime en pantalla son las direcciones
de los elementos del arreglo. Observamos que cada dirección va en aumento de 4
en 4 y, además, son consecutivas, esto es debido a que los elementos del arreglo
son de tipo entero, por lo que su almacenamiento en memoria es de 4 byte y como
sabemos, la manera de almacenamiento en memoria de los elementos de un arreglo
es consecutiva. Por lo tanto, lo que se nos muestra en la salida, es dirección de
memoria de los elementos del arreglo en bytes.
Lo segundo que identificamos son los valores de las posiciones del arreglo. Los
valores son consecutivos del elemento [0] al [4], y van del 35 al 55 aumentando de
cinco en cinco, pero a partir de ahí, los valores del [5] al [9], son generados
aleatoriamente y los valores son basura de la memoria. Esto es debido a que, en el
código, en la línea 5, solo se inicializo al arreglo con 5 valores y a la hora de
imprimirlo, en la línea 11, se indico con el ciclo for de imprimir 10 elementos. Es por
esto, que el arreglo tomo valores basura. Cabe señalar que estas instrucciones se
logran gracias a que el arreglo, a la hora de ser declarado en la línea 5, no se colocó
el número de elementos máximos, sino más bien, se dejaron en blanco los
corchetes permitiendo que podamos darle los elementos que nosotros queramos.
Para hacer la modificación del código, lo que hicimos fue cambiar la palabra
reservada malloc por calloc y agregar el segundo parámetro con la ayuda de sizeof,
para no tener errores:
En este caso, como se nos pide darle valores de múltiplos de 3 a las localidades
reservadas de memoria dinámica, modificaremos el código para que el apuntador
ptr contenga estos valores. Por lo tanto, lo que necesitamos es un ciclo for y una
variable que sirva para reservar los valores de tres en tres.
*(ptr + cont)=variable;
Seguida por:
variable+=3;
Ya como último, hablaremos de la instrucción de la línea 18, la que nos permite que
el apuntador vaya tomando valor de múltiplos de 3. Como sabemos, esto
corresponde al operador suma asignación “+=”, que toma la expresión de la
izquierda, en este caso variable con valor de 3, y suma una constante, lo que
aparece después del operador, en este caso 3. Para que al final le asigne a la misma
expresión de la izquierda el resultado de la suma. Si hacemos esto dentro de un
ciclo for, lo que pasara es que, en cada recorrido, a variable se le sumara un 3 y
como su valor inicial es 3, obtendremos puros múltiplos de este número, hasta
acabar el recorrido del ciclo.
Como podemos ver, los valores del apuntador que se nos muestran son los
indicados, pues corresponden a múltiplos de 3, iniciando por el mismo 3.
Imprime las direcciones y los valores del apuntador obtenido con realloc
Lo primero que se realizó, fue asignarle al mismo apuntador ptr, un tamaño nuevo
con la función realloc, como vemos en la Figura 10, línea 31. El uso fue sencillo,
escribimos al apuntador sin su operador indirección (*), y procedemos a asignarle
el nuevo tamaño con realloc. Sabemos que realloc recibe dos parámetros, el
primero es el apuntador por redistribuir y el segundo que es el nuevo tamaño, en
bytes, que, para este caso, nos apoyamos de sizeof para no obtener errores.
Para dar solución a lo segundo que se nos pide, seguiremos casi el mismo
procedimiento que en la línea 31, pero con la diferencia de que ahora no usaremos
el mismo apuntador, sino mas bien, usaremos al apuntador ptr3 para asignar el
nuevo tamaño.
Tanto en la figura 12 y 13, podemos ver que en la salida de los valores del apuntador
ptr y ptr3, respectivamente, se siguen manteniendo intactos a como fueron
asignados previamente, recordando que se habían reservado 10 huecos de
memoria con valores múltiplos de 3. Esto es un ejemplo de una ventaja de realloc,
ya que como vimos, además de aumentar en tiempo de ejecución el tamaño de
memoria, conserva los valores que anteriormente fueron asignados. Cabe señalar
que los valores restantes fueron asignados a 0, debido a que en la línea 8, se hace
uso de la función calloc para asignarle los espacios de memoria a ptr, por lo tanto,
calloc es el responsable de limpiar la memoria y asignar los ceros, y, por ende, esto
se hace valido a la hora de usar realloc.
Otra cosa que resulta muy interesante es el análisis entre la asignación de un nuevo
tamaño en el mismo apuntador, ptr, y la asignación con otro apuntador (ptr3). Pues
como vemos en la figura 12 y 13, los valores son idénticos a ambos procedimientos
y además apuntan a la misma dirección. Esto es similar al concepto de apuntadores
múltiples, pues básicamente el uso de estos apuntadores es que se pueden
modificar valores de una variable en cualquier apuntador. Además, podemos decir
que en la función realloc, lo que se hace es asignarle un apuntador a otro apuntador,
entonces se puede deducir que, de cierta manera, al hacer uso de la función realloc,
estamos aplicando el concepto de apuntadores múltiples, pero de tipo void.
Algo curioso que sucedió, fue que, en las primeras ejecuciones del programa
modificado, en los valores de los apuntadores con nuevo tamaño, hablando solo de
los que no tenían algo asignado, se encontraba basura, pero al estar ejecutando el
programa para ver si algo fallaba, los resultados en pantalla cambiaron y se
limpiaron a ceros. Me pareció interesante mencionar esto, ya que como el apuntador
ptr, fue asignado con la función calloc, lo esperado es que los valores se limpiaran
y se les asignara ceros, pero como se mencionó, al inicio mostro valores basura y
después se solucionó este pequeño error, sin tener nada que hacer. Se desconoce
lo que dio origen a esto, seguramente fue que esos espacios de memoria no se
pudieron liberar o limpiar al inicio. Lamentablemente no se pudo capturar este
extraño caso, así que solo lo consideraremos como una nota.
Ejercicio 2.
Y por último tenemos lo que pasa con realloc. Podemos ver que este es un nuevo
apuntador con un tamaño diferente a los otros, ya que este cuenta con 10 espacios
reservados, mientras que los dos primeros solo contaban con 5. Asi mismo,
analizando muy detalladamente, vemos que los valores de las primeras direcciones
del apuntador din3, son idénticas a las del apuntador din2, por lo que podemos ir
deduciendo que hubo un aumento de memoria de din2, el cual fue realizado por la
función realloc y asignado a din3. Para entender mejor esto, nos apoyaremos del
código para explicar lo que ocurre. Por lo tanto, si nos remontamos a la línea 24 del
código, veremos que al arreglo din3, se le esta dando un nuevo tamaño con la
función realloc, utilizando al apuntador din2 que anteriormente fue asignado con
calloc. Al ver esto, entonces podemos entender por qué las primeras 5 direcciones
del apuntador din3, son las mismas a las del apuntador din2.
c. Agrega las instrucciones al código para pedir al usuario los datos de los
alumnos que se reservan en el programa
Para este inciso, lo que haremos es ocupar un código aparte, que lleve la misma
forma que el código que veníamos utilizando, pero con todas las modificaciones que
se irán haciendo, esto lo hacemos por comodidad.
Lo primero que se hizo fue borrar las líneas que no se necesitaban y que
consideraba, que estaban demás. Lo que, si conservamos del código base, fue tanto
la declaración de los apuntadores din1, din2 y din3, como la asignación de su
tamaño de memoria con malloc, calloc y realloc.
Ya dentro de Alumno1.h, nos vamos a la 28 y 65, veremos que son las funciones
que usamos para asignarle valores a los alumnos de din1 y din2. Cabe mencionar,
que para mas comodidad y no llegarse a perder, se separaron en funciones
individuales a los apuntadores, para asignar con mas facilidad los valores de sus
miembros. Ahora, básicamente lo que se realizó en cada función, fue ir agregando
scanf, para ir pidiendo los valores correspondientes, todo esto dentro de un ciclo for,
el cual los permite recorrer cada apuntador. Además, al final de cada ciclo,
agregamos un system("PAUSE"); y system("cls"); lo cuales le dará una cierta
estética a la ejecución, ya que uno pausara el ciclo, lo cual nos permite ver los datos
agregados y después de continuar, la siguiente instrucción se encarga de limpiar la
salida.
Ya como una de las ultimas cosas, veremos que en el código main, mandamos a
llamar nuestras funciones que sirven para imprimir cada elemento asociado a
nuestro apuntador y que funcionan de manera tradicional, vamos colocando printf,
junto con la sentencia que se muestra en pantalla y después ponemos como
parámetros, al apuntador con el operador flecha, que nos ayuda a indicar a que
miembro de la estructura estamos haciendo referencia y que solo se usa en
apuntadores.
Figura 15. Función asignarAlumno en ejecución, asignación del primer alumno de din 1.
Figura 16. Función asignarAlumno en ejecución, asignación del segundo alumno de din 1.
Figura 17. Función asignarAlumno en ejecución, asignación del tercer alumno de din 1.
Figura 18. Función asignarAlumno en ejecución, asignación del cuarto alumno de din 1
Figura 19. Función asignarAlumno en ejecución, asignación del quinto alumno de din 1
Figura 20. Función asignarAlumno2 en ejecución, asignación del primer alumno de din2.
Figura 21. Función asignarAlumno2 en ejecución, asignación del segundo alumno de din2
Figura 22. Función asignarAlumno2 en ejecución, asignación del tercer alumno de din2
Figura 23. Función asignarAlumno2 en ejecución, asignación del cuarto alumno de din2
Figura 24. Función asignarAlumno2 en ejecución, asignación del quinto alumno de din2
Con esto termina la ejecución de la función para din2 y nos vamos con la instrucción
de la línea 15. La asignación de valores a din3, que previamente fue
redimensionado. Recordemos que como din3, contiene a los valores primeros
valores de din 2, solo el usuario asignara los otros 5 restantes.
Figura 25. Función asignarAlumno3 en ejecución, asignación del sexto alumno de din3
Figura 26. Función asignarAlumno3 en ejecución, asignación del séptimo alumno de din3
Figura 27. Función asignarAlumno3 en ejecución, asignación del octavo alumno de din3
Figura 28. Función asignarAlumno3 en ejecución, asignación del noveno alumno de din3
Figura 29. Función asignarAlumno3 en ejecución, asignación del décimo alumno de din3
Ya por último, lo que el programa nos presenta en pantalla son los datos de los
alumnos previamente asignados, por lo tanto, la salida final de programa es la
siguiente:
Lo que podemos hacer en este caso, es apoyarnos de las funciones que nos ayudan
al uso de memoria dinámica. Como nosotros queremos liberar la memoria reservada
por las funciones calloc y malloc, la única función que nos queda “disponible” es
realloc. Por lo tanto, lo que se me ocurre es aplicar esta función, que redefine el
número de los espacios reservados, asignándolos al mismo apuntador o a otro. Así
pues, lo que haremos es colocar un cero en el segundo parámetro de cada función
realloc y asignarle ese nuevo tamaño al mismo apuntador. Básicamente le
estaremos diciendo a realloc que nos reasigne cero espacios reservados en los
mismos apuntadores, es por eso, que cuando usamos realloc en din1, din2 o din3,
el primer parametro que se le concede es el mismo apuntador, respectivamente,
como se ve en la siguiente figura:
Como podemos darnos cuenta, ahora las direcciones de cada elemento no apuntan
a una dirección en específico, como se muestra en la figura 14 y lo que paso ahora,
es que solo muestra el tamaño de cada dirección, que como recordaremos, el
tamaño del objeto es de 88 bytes, por eso es por lo que nos muestra valores de 88
en 88. Por lo tanto, la memoria queda liberada.
Ejercicio 3.
Lo que se hizo para este ejercicio, fue primero realizar nuestra biblioteca
Automovil.h, donde tenemos a nuestras funciones y a nuestro tipo de datos
abstracto. De la línea 5 a la 11, vemos nuestra declaración de la estructura, de
manera sencilla, aplicamos typedef y como miembros, colocamos los datos
esenciales para identificar a un automóvil. Después de esto, realizamos nuestras
funciones, una para llenar los datos y otra para imprimirlos. Como vemos, estas
funciones recibirán dos paramentos, uno será un apuntador de tipo Automóvil, que
se encuentra en nuestra main y el segundo será un valor entero, el cual será nuestra
variable que usamos para indicar el máximo de espacios reservados por el usuario.
Algo que me pareció muy importante en este aprendizaje, fue el uso de librería,
pues hasta este momento nunca había aplicado este concepto, el cual se me hace
de suma importante, pues gracias a él, podemos reducir el tamaño de nuestro main
y nos facilitara mucho el manejo de programas.