PI-ITBA / 2024_02

Consultas 2C 2024
4 stars 0 forks source link

Consulta Ej. 20 Guia 7 (Resolución cátedra) #83

Open HoltzTomas opened 2 weeks ago

HoltzTomas commented 2 weeks ago

Dudas resolución cátedra

Dejo un par de dudas sobre la resolución que esta subida del ejercicio 20 guía 7.

alumAux = realloc(alumAprob, (cantAprob + BLOCK) * sizeof(char *));

// Y despues

alumAprob = realloc(alumAprob, (cantAprob+1) * sizeof(char *));
alumAprob[cantAprob] = "";

Código completo

#include <stdlib.h>
#include <string.h>
#include <errno.h>

#define BLOCK 10
#define NOTA_MINIMA 4
typedef char * TAlumnos[];

void liberaAprobados(char **alumnos)
{
    /* Liberar los strings excepto el string vacio (ya que era constante) */
    for (int i = 0; *alumnos[i]; i++)
        free(alumnos[i]);

    free(alumnos);
}

/* Para definir “alumnos” como "matriz" de char usar
** #define MAX_NOMBRE 15
** #define MAX_ALUMNOS 6
** typedef char Talumnos[MAX_ALUMNOS][MAX_NOMBRE]; */

// En esta versión validamos los malloc y realloc, como ejemplo. 
// No es necesario que hagan estas validaciones en los parciales (sí en el final)

char **
aprobados(TAlumnos alumnos, int notas[])
{
    int cantAprob = 0;
    char **alumAprob=NULL, **alumAux;

    errno = 0;
    for (int i = 0; alumnos[i][0] != '\0'; i++) {
        if (notas[i] >= NOTA_MINIMA)
        {
            /* Si no hay lugar en el vector, agrandarlo */
            if (cantAprob % BLOCK == 0)
            {
                alumAux = realloc(alumAprob, (cantAprob + BLOCK) * sizeof(char *));

                /* Si no hay memoria no hay nada que se pueda hacer 
                ** NOTA: agregamos esto pero no será necesario que lo hagan en el parcial, sólo en el TPE
                */
                if (alumAux == NULL || errno == ENOMEM)
                {
                    if ( cantAprob > 0) { // Por si el que falla es el primer realloc, y alumAprob sigue en NULL
                        /* Hay que liberar todo, tambien los strings */
                        alumAprob[cantAprob] = "";
                        liberaAprobados(alumAprob);
                    }
                    return NULL;

                }
                alumAprob = alumAux;
            }
            /* Copiar el string. Como son cortos usamos strlen y luego strcpy */
            alumAprob[cantAprob] = malloc(strlen(alumnos[i]) + 1); 
            if (alumAprob[cantAprob] == NULL  || errno == ENOMEM)
            {
                alumAprob[cantAprob] = "";
                liberaAprobados(alumAprob);
                return NULL;
            }
            strcpy(alumAprob[cantAprob++], alumnos[i]);
        }
    }

    /* Copiar el string vacio al final, y liberar lo que sobra del bloque final */
    alumAprob = realloc(alumAprob, (cantAprob+1) * sizeof(char *));
    alumAprob[cantAprob] = "";

    return alumAprob;
}
ImNotGone commented 2 weeks ago

Usa el auxAlum para no pisar alumAprob y asi no perder la referencia en caso de que el realloc falle. Al no perder la referencia puede liberar la memoria previamente utilizada.

En cuanto a la 2da pregunta todos los strings cte que definas, ya sean "hola", "tomas" o "" son direcciones de memoria que apuntan a la seccion readonly de tu programa en ejecucion entonces en definitiva pueden asignarse a cualquier puntero.

Si no quedo claro intento ir en mas detalle :D.

HoltzTomas commented 2 weeks ago

Sisi me imaginaba que iba por ahí la primera parte, pero me hace ruido justamente porque después no lo hace (imagino que por el tema de que salvo en el final no hace falta chequear nada).

Lo segundo se entendió joya, gracias che.

ImNotGone commented 2 weeks ago

Es para liberarla en el fallo osea cuando entra al if pq realloc le devolvio null o errno esta en ENOMEM

HoltzTomas commented 2 weeks ago

Si bueno, pero el tema está en esta línea al final

alumAprob = realloc(alumAprob, (cantAprob+1) * sizeof(char *));

Hay un caso en el que esta línea no estaría reduciendo, sino aumentando el tamaño en una posición, esto podría dar error y tendríamos que hacer lo mismo que arriba.

Me llamaba la atencion que ahí no lo haga, pero supongo que fue porque en el primer caso fue en modo ilustrativo basandome en el comentario

// En esta versión validamos los malloc y realloc, como ejemplo. 
// No es necesario que hagan estas validaciones en los parciales (sí en el final)
marcelogarberoglio commented 2 weeks ago

Exacto, está como un ejemplo de hacer el realloc validando, guardando primero en una auxiliar. De todos modos, hay que tener demasiada mala suerte para que tengas memoria suficiente para cientos o miles de punteros pero no para uno más.

HoltzTomas commented 2 weeks ago

Programación defensiva 😅

marcelogarberoglio commented 2 weeks ago

Sólo de lunes a viernes en horario de oficina.

ImNotGone commented 2 weeks ago

Jajajsjsjs