Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Open
HoltzTomas opened this issue Oct 4, 2024 · 8 comments
Open

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

HoltzTomas opened this issue Oct 4, 2024 · 8 comments

Comments

@HoltzTomas
Copy link

Dudas resolución cátedra

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

  • Porque en primera instancia se utiliza auxAlumn para guardar el nuevo puntero en lugar de hacer lo que se hace al final de simplemente reasignándolo a alumAprob. Ósea:
alumAux = realloc(alumAprob, (cantAprob + BLOCK) * sizeof(char *));

// Y despues

alumAprob = realloc(alumAprob, (cantAprob+1) * sizeof(char *));
  • Si alumAprob es un puntero a puntero (char **), me parece raro que funcione alumAprob[cantAprob] = "";, ósea me parece raro poder asignarle una cadena constante en lugar de una dirección de memoria. Porque eso funciona?
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
Copy link
Contributor

ImNotGone commented Oct 4, 2024

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
Copy link
Author

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
Copy link
Contributor

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

@HoltzTomas
Copy link
Author

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
Copy link
Member

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
Copy link
Author

Programación defensiva 😅

@marcelogarberoglio
Copy link
Member

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

@ImNotGone
Copy link
Contributor

Jajajsjsjs

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants