Está en la página 1de 34

Carátula para entrega de prácticas

Facultad de Ingeniería Laboratorio de docencia

Laboratorios de computación
salas A y B
M.I Edgar Tista García
Profesor:

Estructura de Datos y Algoritmos 1


Asignatura:

01
Grupo:

04
No de Práctica(s):

González González Pedro José


Integrante(s):
No. de Equipo de
Trabajo en casa
cómputo empleado:

24
No. de Lista o Brigada:

2022-2
Semestre:

Fecha de entrega:

Observaciones:

CALIFICACIÓN: __________
Objetivos
Objetivo general:

Utilizaras funciones en lenguaje C que permiten reservar y almacenar información


de manera dinámica (en tiempo de ejecución).

Objetivo de la clase:

Comprender el uso básico de apuntadores aplicado al almacenamiento en tiempo


de ejecución, así como las funciones esenciales para el trabajo de los mismos
Desarrollo
Actividades previas:

Ejercicio 1 – Código (malloc).

El primer ejercicio que nos presenta es la ejemplificación de la función malloc y free


en el uso de la memoria dinámica en el lenguaje C. Este lenguaje nos permite hacer
uso del almacenamiento de memoria en tiempo de ejecución a través de tres
funciones; la cual una de ellas es malloc.

Básicamente, la forma más habitual de C para obtener bloques de memoria es la


función malloc. La función asigna o reserva un bloque de memoria, los cuales son
el número de bytes pasados como argumentos, y devuelve un apuntador de tipo
void, que es la dirección del bloque asignado.

Para este caso, en particular, lo que hace el programa es seguir los tres pasos de
los apuntadores.

Paso 1: En la línea 8, declara al apuntador: *arreglo.

Paso 2: En la línea 11, se reemplaza la asignación del apuntador a una


variable del mismo tipo, por la asignación para la función de memoria
dinámica. Entonces, lo que el código hace es asignar al apuntador void, el
tipo de dato con el que se trabajará mediante la función malloc y después se
indica el número de espacios para almacenar el tipo de dato que se solicitó,
con la ayuda de sizeof:

arreglo = (int *)malloc (num * sizeof(int));

Es importante recordar: que un apuntador de tipo void puede asignarse a


una variable de cualquier tipo, y también, que la función sizeof devuelve el
tamaño de una variable en bytes, lo cual nos ayuda por si no recordamos el
tamaño de un byte de tipo entero, flotante, etc.

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.

Otros puntos que resultan interesantes analizar son:

En la línea 12: Se uso la instrucción if que lleva dentro la condición


arreglo!=NULL, la cual nos indica que si el apuntador no apunta a ninguna
dirección, no dará ningún resultado. Podemos decir que esta instrucción esta
demás, ya que al inicializar el apuntador arreglo este siempre será asignado
a la dirección del tipo de dato que le diga malloc.

El uso de las bibliotecas, en las líneas 3 y 4. La biblioteca stdlib.h se agrego


debido a que la función malloc se encuentra contenida en esta y la biblioteca
locale.h se implementó como modificación del código para el uso de
caracteres como la ñ, el acento, etc. (código ASCII extendido).

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:

Figura 1. Ejecución del ejercicio 1 del manual.

Como podemos ver, nos pide el numero de elementos que se reservaran en


memoria dinámica, como ya lo explicamos anteriormente y nos da el vector o
apuntador reservado, pero con valores cualquiera. Al final nos indica que el espacio
reservado se libera, pues es cuando el programa hace uso de la función free, la cual
es importante pues si no lo usamos, pueden surgir errores. Lo cual nos lleva a dar
por terminado el ejemplo
Ejercicio 2 – Código (calloc)

Tras codificar y ejecutar el código dado, la salida en pantalla que nos muestra es la
siguiente:

Figura 2. Salida del código (calloc) - Ejercicio 2 del manual

Como ponemos darnos cuenta, lo que el programa hace es darnos un ejemplo de


cómo funciona la función calloc. Esta función es la segunda de las tres funciones
que nos permite hacer uso de la memoria dinámica en lenguaje C. El concepto de
calloc es “similar” a malloc, pues se puede asignar memoria como con malloc, pero
cambia la forma de asignar el numero de bytes al apuntador de tipo void. Recibe
como argumentos dos parámetros, el primero es el número de espacios a reservar
y el segundo es el tamaño de cada elemento. Estas instrucciones se encuentran en
la 11 del código:

Figura 3. Función calloc aplicada al ejercicio

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.

Ya para finalizar, cabe decir que se modifica el ejemplo, agregándole la biblioteca


locale.h para el uso de caracteres especiales en español. Por lo tanto, damos por
finalizado el segundo ejemplo.
Ejercicio 3 – Código (realloc)

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:

Figura 4. Ejecución del ejercicio 3 - Código realloc.

Como podemos ver, lo que el programa hace es pedirnos el tamaño de los


elementos que se reservaran en memoria. Después nos pide sus valores y al acabar
e imprimir el primer vector, hace uso de la función realloc para aumentar el tamaño
del conjunto de elementos al doble y pedir los valores de los elementos agregados.

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.

Después de la asignación del apuntador arreglo, como la condición if siempre será


cierta, pues el apuntador siempre apunta a algo, se hace uso de un ciclo for, el que
recorrerá los elementos del apuntador para que el usuario le asigne valores en
teclado. Lo que pasa de la línea 17 a la 21, es imprimir el vector volviendo a usar un
ciclo for para hacer el recorrido de sus elementos.
Figura 5. Instrucciones para el primer apuntador.

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.

La función realloc, nos permite redistribuir un área o conjunto de memoria la cual


previamente fue asignada por malloc o calloc. Para esto, lo que realloc sigue es la
siguiente sintaxis:

void *realloc (void *ptr, size_t size);

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.

Ahora bien, en la línea 24 se encuentra el uso de la funcion. Vemos que se le está


asociando al arreglo2 un nuevo tamaño de localidades con la funcion realloc, las
cuales serán de tipo entero. En los parámetros observamos que primero coloca el
apuntador antes reservado por malloc y para el segundo parámetro, se coloca el
tamaño de bytes del tipo de dato requerido (dado por sizeof), por el numero de
elementos que queremos, que en este caso será el doble. A continuación, se
muestra la imagen que contiene lo anteriormente descrito:

Figura 6. Manera de usar la función realloc

Después de redimensionar el apuntador con arreglo2, lo que hace el programa es


entrar a la condición de la línea 25, para que así se le pueda dar valores al nuevo
apuntador desde el elemento en el que se quedó. En la línea 27, el ciclo for tiene
una forma especial, pues no tiene la primera instrucción con la que habitualmente
se usa, asumimos que esto es para que el ciclo for comience desde el elemento en
el que se quedo el apuntador anterior, por ejemplo: si nosotros decidimos tener un
apuntador de 3 elementos al inicio y le colocamos valores a estos elementos, a la
hora de redimensionar el apuntador, ya no iniciaríamos dándoles valores desde el
primer elemento, sino que estos se guardarían y le estaremos dando valores a los
elementos 4,5 y 6.

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.

Respondiendo las preguntas indicadas:

a. Captura la pantalla con la ejecución del programa y explica de manera


detallada, los resultados que se observan.

Tras compilar y ejecutar el código dado, la salida que se nos muestra en pantalla es
la siguiente:

Figura 7. Ejecución del código "ejercicio1"

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.

Continuando con el análisis, tenemos la impresión de la dirección del apuntador ptr.


Similar a lo que paso con las direcciones del arreglo, podemos darnos cuenta de
que la dirección va en aumento de 4 en 4 y que son consecutivas, de igual forma
que con el arreglo, esto se debe a que, al ser un apuntador que hace referencia a
tipo de datos enteros, los bytes en memoria con los que se almacenan son 4.
Siguiendo con los valores del apuntador, podemos ver que imprime valores
cualesquiera, pues como no se le asignaron en algún momento, apunta a los valores
que en algún momento se encontraban en esas direcciones o eran basura.

b. Modifica la asignación inicial de “*ptr” de tal modo que ahora se utilice la


función calloc, compila, ejecuta y explica la diferencia con la ejecución previa.

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:

𝑖𝑛𝑡 ∗ 𝑝𝑡𝑟 = 𝑚𝑎𝑙𝑙𝑜𝑐(10); → 𝑖𝑛𝑡 ∗ 𝑝𝑡𝑟 = 𝒄𝒂𝒍𝒍𝒐𝒄(10, 𝒔𝒊𝒛𝒆𝒐𝒇(𝒊𝒏𝒕));

Una vez hecha la modificación, compilamos y ejecutamos, obteniendo la siguiente


salida:

Figura 8. Ejecución del código, tras la modificación del inciso b


Como podemos observar, las salidas con respecto al arreglo siguen intactas, pero
los resultados con el apuntador son diferentes. Como primera observación, tenemos
que las direcciones cambiaron, siguen aumentando de 4 en 4, pero tienen diferentes
valores, por lo tanto, podemos decir que la función calloc, toma diferentes huecos
de memoria a los que toma malloc. Además de estas diferencias, tenemos la mas
importante y relevante: los valores del apuntador están inicializados en 0. Esto esta
relacionado con el concepto de la función calloc y su principal diferencia con malloc,
pues como indicamos anteriormente, en las actividades previas, lo que hace calloc
es limpiar la memoria para asignar ceros en los valores iniciales del apuntador. Por
esta diferencia clave entre calloc y malloc, es que los valores del apuntador, en esta
ejecución, son ceros.

c. Agrega instrucciones para asignar valores en las localidades de memoria


reservadas con memoria dinámica. (deberás asignar valores múltiplos de 3
(3,6,9…) Se deberá mostrar en pantalla los valores asignados y la dirección
de éstos

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.

Lo primero que se hizo, fue modificar a la variable de nombre variable, valga la


redundancia, que se encuentra en la línea 6. Inicializamos a variable con el valor 3,
pues como el programa nos pide múltiplos de 3, utilizaremos esta variable para
llevar el proceso acabo. Como siguiente paso, agregamos el ciclo for que se
encuentra en la línea 16 a la 19, ya que necesitamos recorrer los espacios
reservados para asignarles sus valores correspondientes. Ya dentro de este ciclo,
colocamos nuestra instrucción clave:

*(ptr + cont)=variable;

Seguida por:

variable+=3;

Con la primera instrucción, lo que estamos haciendo es asignarle el valor de variable


al apuntador, que ira incrementando de tres en tres gracias a la instrucción que le
sigue. Algo importante a considerar, es que el apuntador tiene a un índice (cont),
esto se debe a que necesitamos de algo para recorrer las direcciones de memoria
reservadas en ptr, por lo tanto, nos apoyamos de un índice que nos indica a que
valor estamos apuntando.

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.

Tras compilar y ejecutar el código, obtenemos la siguiente salida:

Figura 9. Ejecución del ejercicio 1, con modificaciones del inciso c.

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.

d. Agrega instrucciones para utilizar la función realloc para redimensionar “ptr”


con un nuevo tamaño de 25 espacios

• Utiliza realloc para asignar el nuevo tamaño en el mismo apuntador ptr


• Utiliza realloc para asignar el nuevo tamaño en el apuntador ptr3

Imprime las direcciones y los valores del apuntador obtenido con realloc

Indica si se conservan los valores que se habían asignado previamente

Finalmente indica si hay diferencias entre asignar realloc al mismo apuntador


(ptr) o a uno nuevo (ptr3)
La tarea primero se abordo declarando el apuntador ptr3, para trabajar con él, lo
que se nos pide. Posteriormente comentamos las líneas de programa que estaban
de más, las cuales corresponden a la impresión de las direcciones y valores del
arreglo. Conservamos la asignación de valores múltiplos de 3, del inciso anterior, y
mandamos a imprimir con un ciclo for, las direcciones y valores del arreglo ptr, con
el fin de que, en la salida, podamos observar de mejor manera como es que función
realloc.

Posteriormente, pasamos a utilizar realloc para la asignación de un nuevo tamaño


en los apuntadores, como se muestra en la siguiente imagen:

Figura 10. El uso de 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.

Ya para finalizar, mandamos a imprimir a los apuntadores obtenidos. Primero


imprimiremos a ptr con el nuevo tamaño. Utilizamos un ciclo for, pero en esta vez,
el segundo parámetro o el valor final cambia a 25, pues recordemos que nos piden
el aumento de tamaño a 25. Colocamos nuestro printf y salimos de este primer ciclo
for. Continuando con el final del programa, pasamos a imprimir nuestro segundo
arreglo obtenido: ptr3. De igual forma que con el anterior apuntador, usamos un ciclo
for, con valor final a 25 y dentro de este, colocamos nuestro prinft para ver tanto las
direcciones y valores de apuntador ptr3. Salimos del último ciclo, y como buena
práctica, liberamos los espacios de memoria reservados por lo apuntadores, con la
función free

Por lo tanto, una vez modificado el programa, compilamos y ejecutamos el código,


obteniendo la siguiente salida:
Figura 11. Primera parte de la salida del programa

Figura 12. Segunda parte de la salida del programa


Figura 13. Tercera parte de la salida del programa

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.

Respondiendo las preguntas indicadas:

a. Explica los resultados que se muestran en pantalla.

Compilando y ejecutando el programa, la salida en pantalla es la siguiente:

Como podemos ver, lo primero que


imprime el programa es el tamaño
de la estructura Alumno, en bytes.
Lo siguiente que nos muestra en
pantalla, son las direcciones de los
valores asignados en el apuntador
din1, mediante la función malloc.

Si nos vamos al código,


específicamente en la línea 8,
podemos ver que se le asignaron 5
espacios de memoria de Alumno,
nuestra librería codificada,
mediante el uso de memoria
dinámica. Es por esto por lo que se
nos muestra 5 direcciones.

También resulta importante la


manera en que las direcciones se
van presentando, pues si nos
podemos a analizar con detalle
cada dirección, nos daremos
cuenta de que van incrementando
de 88 en 88, lo que corresponde al
Figura 14. Salida en pantalla del ejercicio 2. tamaño de una estructura Alumno.
Con esto, podemos entender que
las asignaciones de los espacios de
memoria se presentan continuamente y que, además, sus direcciones van
incrementando según el tamaño de tipo de dato al que se esta asociando.

Continuando con los resultados, para el segundo apuntador pasa prácticamente lo


mismo, nos da la dirección de los 5 espacios de memoria reservados, y al estar
asociados al objeto Alumno, incrementan de 88 en 88. Hay que indicar que las
direcciones si son diferentes, pero siguen el mismo patrón de incremento que con
el apuntador anterior.

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.

b. ¿Cuál es el tamaño de la estructura Alumno? ¿Cómo se obtiene ese tamaño?

Como nos indica el mismo programa en su salida, el tamaño de la estructura


Alumno es de 88 bytes, y esto se obtiene con la sentencia sizeof, la cual devuelve
el tamaño de una variable en bytes. Como vemos, en la línea 6, la sentencia sizeof
se aplica a un printf, con una marca de tipo %d, para que posteriormente se agregue
como parámetro la sentencia sizeof, que nos dará el tamaño de la estructura en
bytes.

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.

Por lo tanto, como primeros pasos, declaramos nuestros apuntadores (línea 7) y


después, le asignamos a din1 y din2, los espacios de memoria reservada. Lo
siguiente que hicimos, fue hacer uso de funciones para que el usuario pueda asignar
los datos correspondientes a los alumnos. Estas funciones, las llamamos en la línea
11 y 12, pero las alojamos dentro de nuestra biblioteca Alumno1.h, la cual, es la
biblioteca Alumno.h, pero modificada para que en estas se encuentren las funciones
a usar.

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.

Nos regresamos al main, porque si no nos percatamos, hasta el momento


estábamos dejando de lado la asignación de din3. Esto se hizo con la finalidad de
poder ahórranos tiempo, pues como din3 estaba siendo reasignado con realloc,
tomando como parámetro a din2, podemos utilizar los valores de din2 y solamente
asignarle los valores restantes, que en este caso serian 5 más. Es por esto, que
primero colocamos la función que asigna valores a din2 y así tomarlos en din3.
Ahora sí, mandamos a llamar a la función que llenara al apuntador din3 y nos vamos
a Alumno1. h. Dentro de este código, nos vamos hacia la línea 102 y veremos todo
el cuerpo de la función, que es muy similar a las otras funciones, mediante un ciclo
for, vamos recorriendo los espacios asignados y le daremos su valor, así hasta llenar
todos los elementos.

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.

Una vez acabamos de imprimir nuestros apuntadores, nos regresamos a nuestro


main para liberar los huecos de memoria que ya no son usamos, mediante la función
free. Es importante remarcar esto, pues cada vez que hacemos uso de memoria
dinámica, es necesario, liberarla.

A continuación, mostraremos la ejecución en pantalla, de todo lo antes mencionado:

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

Aquí finaliza la función asignarAlumno, ya que todos los alumnos de din1, se


encuentran asignados. Por lo tanto, entramos a la instrucción de la línea 12 del
código main.

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:

Figura 30. Salida de los alumnos de din1, parte 1.


Figura 31. Salida de los alumnos de din1, parte 2.

Figura 32. Salida de los alumnos de din2, parte 1


Figura 33. Salida de los alumnos de din2, parte 2

Figura 34. Salida de los alumnos de din3, parte 1


Figura 35. Salida de los alumnos de din3, parte 2

Figura 36. Salida de los alumnos de din3, parte 3


d. Explica de qué forma se podría liberar la memoria reservada por la función
calloc o malloc sin utilizar la función free, realiza el intento en código e indica
tus resultados.

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:

Para comprobar que, si se hayan liberado correctamente los espacios reservados,


imprimiremos las direcciones de cada apuntador después de las instrucciones de
las líneas 32,33 y 34, por lo que, la salida que nos muestra es la siguiente:

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.

Siguiendo en Automovil.h, veremos que en la línea 16, colocamos las instrucciones


que tendrán nuestra función llenarDatos. Como venimos trabajando, esta funcione
contiene scanf para la lectura de cada elemento asignado por el usuario, los cuales
de encuentran dentro de un ciclo for, que comienza en cero y terminara e n el valor
que el usuario indico.

Una vez finalizada la función llenarDatos, nos vamos a la función imprimirAutos, la


cual es muy sencilla, pues usando un ciclo for, estará imprimiendo cada dato de los
coches. Usando el operador flecha para hacer referencia a los miembros de nuestro
tipo de dato abstracto y además, se uso una sentencia if, para que dependiendo del
valor de (automoviles+i)->transmisión, imprima si es de transmisión manual o
automática.

Ya en el código principal, dentro del main, lo único que hacemos, es declarar un


apuntador de tipo Automóvil, al cual le asignaremos el tamaño de espacios
reservados que nos de el usuario. Posteriormente, lo que hace es solo llamar a las
funciones para que ejecuten sus instrucciones y al final, libera la memoria
reservada.

La ejecución del programa es la siguiente:

Figura 37. Asignación del primer automóvil, con la función llenarDatos


Figura 38. Asignación del segundo automóvil, con la función llenarDatos

Figura 39. Asignación del tercer automóvil, con la función llenarDatos

Figura 40. Impresión del garaje completo


Conclusiones
Al término de la práctica, podemos decir que los objetivos se alcanzaron de manera
exitosa, pues gracias a la resolución de los ejercicios planteados, los conceptos
vistos en clase y en el manual del laboratorio, quedaron fuertemente entendibles.
Así mismo, podemos decir que el ejercicio que nos ayudó bastante fue el primero,
ya que este fue la piedra angular para entender lo que hace cada función en el uso
de memoria dinámica. Considero que la estrategia de entregarnos un código base
y de ahí, empezar a modificarlo, fue una manera muy didáctica de aplicar nuestros
conocimientos en la resolución de lo que se nos pedía.

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.

La práctica fue de sumo agradado, pues se implemento todo lo visto hasta el


momento, lo cual nos permite tapar los huecos de conocimiento que todavía
tendremos, así como también, nos hace ver que podemos realizar programas que
sean de mayor complejidad para un programador principiante, pero para nosotros
ya es algo normal.

Con todo lo visto, tanto en la teoría, en el ejercicio y en esta práctica, logramos


entender todo el funcionamiento de las funciones malloc, calloc y realloc, que hasta
inclusive, descubrimos una nueva función para realloc
Bibliografía
Aguilar, L. J. (2014). Programación en C, C++, Java y UML (2nd Edition). McGraw-Hill
Interamericana. https://bookshelf.vitalsource.com/books/9781456225452

Solano, J. A. (2017). Manual de prácticas del laboratorio de Estructuras de datos y


algoritmos I (1.a ed.). Facultad de Ingeniería, UNAM.
https://acrobat.adobe.com/link/review?uri=urn:aaid:scds:US:41db7523-8280-3016-89ce-
c17ede2dfc0c

También podría gustarte