marcelogarberoglio / PI

Para realizar consultas
6 stars 0 forks source link

Ej2 RP2 1C 2022 #64

Closed ThomasR62875 closed 1 year ago

ThomasR62875 commented 1 year ago

Hola me puse a hacer el recu del segundo parcial del cuatri pasado. Queria saber si estaba bien

typedef struct frase{
    char *who;
    char *phrase;
    struct frase * tailp;
} Phrase;

typedef struct categoria{
    char *catname;
    Phrase *primerp;
    struct categoria * tail;
} tCat;

typedef struct wsiCDT{
    tCat *primerc;
    tCat *iterador;
    size_t canttotalfrases;
} ;

#define BLOQUE 5

typedef struct wsiCDT * wsiADT;
/*
*  Retorna un nuevo ADT, en principio sin categorías ni frases
*/
wsiADT newWsi(void)
{
    return calloc(1, sizeof(struct wsiCDT));
}

/* Retorna cuántas frases hay en el juego */
size_t size(const wsiADT wsi)
{
    return wsi->canttotalfrases;
}

/* Agrega una nueva categoría, si es que no existe
** Se asume que la longitud de la categoría no supera los 25 caracteres
** Las categorías, una vez agregadas, no se pueden eliminar
** Retorna 1 si lo agregó, 0 sinó
*/

tCat * addCatREC(tCat * cats, const char * name,  int *flag)
{
    int c= strcasecmp(cats->catname, name);
    if(cats==NULL || c>0){ //pasaron una lista vacia, se llego al final o alfabeticamente ya se paso, asiq creo el nodo con la nueva info y lo devuelvo
        tCat * nuevacat = calloc(1, sizeof(tCat));
        strcpy(nuevacat->catname, name);   //es correcto? o deberia con un for pasar caracter a caracter e ir guardandole memoria con la tecnicna de bloques??
        nuevacat->tail=cats;
        return nuevacat;
    }
    if(c==0){       //se encontro la cateogria asiq no debo agregar nada, solo activo el flag.
        *flag=1;
        return cats;
    }
    //sigo buscando la cateogria.
    cats->tail= addCatREC(cats->tail, name, flag);
}

int addCategory(wsiADT wsi, const char * name)
{   //tengo q usar una funcion recursiva q retorna la lista ordenada alfabeticamente con el nuevo nodo metido donde sea q tenga q ir, la funcion usa cats->tail=searchCat y va colgando tods los nodos
    //la funcion usa un paramtero flag q queda en 0 si la categoria ya estaba, y pasa a uno si no estaba y la agrego.
    int flagc=0;
    wsi->primerc= addCatREC(wsi->primerc, name, &flagc);
    return flagc;
}

/* Agrega una nueva frase a una categoría.
** En cada categoría no puede haber más de una frase del mismo autor
** (sí puede un autor tener frases en distintas categorías)
** Si no se pudo agregar (la categoría no existe o el autor ya tiene una frase
** en la misma) retorna 0 (cero), caso contrario retorna 1 (uno)
*/

void searchCat(tCat * cats, const char * catnew, int * flag, tCat * encontro)
{   //en el falg marca 1 si encontro la categoria, no lo cambia sino
    //si la encuentra iguala a esa categoria el nodo encontro.
    if(cats==NULL){         //llegue al final
        return;
    }
    int c=strcasecmp(cats->catname, catnew);

    if(c==0){                    //encontoro la categortia, asiq la copio en el nuevo nodo, y corto la función
        encontro->catname=cats->catname;
        encontro->tail=cats->tail;
        encontro->primerp=cats->primerp;
        *flag=1;
        return;
    }

    if(cats->tail==NULL){                   //no encontro, y no hay más
        return;
    }
    //no encontro ni llego al fin paso a la proxima cat

    searchCat(cats->tail, catnew, flag, encontro);
}

Phrase * addPhraseREC(Phrase * autores, const char * autor, const char * frase, int * flag)
{   //busco el autor, si lo encuentro activo el flag y no pasa nada, en caso contrario lo meto en donde sea indicado ya q esta ordenadno alfabeticamente
    int c = strcasecmp(autores->who, autor);
    if(autores==NULL || c>0){                   //si termino la lista y no lo encontoro, o si ya se paso alfabeticmanete, lo meto a la lista.
       Phrase * nuevoautor = calloc(1, sizeof(Phrase));
       strcpy(nuevoautor->who, autor);     //misma duda que en el strcpy de addCatREC
       strcpy(nuevoautor->phrase, frase);
       nuevoautor->tailp=autores;
       return nuevoautor;
    }
    if(c==0){               //encontro el autor.
        *flag=1;
        return autores;
    }
    //sigo buscando el autor.
    autores->tailp = addPhraseREC(autores->tailp, autor, frase, flag);
}

int addPhrase(wsiADT wsi, const char * category, const char * author, const char * phrase)
{    //voy a buscar dicha categoria con una funcion recursiva parecida a addCategoryREC, solo q esta en caso de no encotrarla no hace nada, pero cuando la encuentra la guarda en un parametro.
    int flagc=0, flaga=0;
    tCat * catParametro;
    searchCat(wsi->primerc, category, &flagc, catParametro);
    if(flagc==1){                                //encontro la categoria asiq ahora busco si ya esta el autor
        //para buscar el autor creo una funcion similar a addCatREC.
        catParametro->primerp= addPhraseREC(catParametro->primerp, author, phrase, &flaga);
        wsi->canttotalfrases++;
    }

    return  flagc && !flaga; //devuelve uno solo cuando se encuentra la cat, y no el autor (osea q se lo agrega).
}

/* Retorna un vector con todos los autores de una categoría (nombre y apellido),
** en orden alfabético ordenados de menor a mayor
** Como marca de final el vector contiene NULL
*/

void creaRta(Phrase * phrase, char ** rta, int * dimrta, int * cantautores)
{   //copio el autor del nodo, y paso al proximo hasta llegar al final
    if(phrase==NULL){        //legue al final asiq corto
        return;
    }
    int i;
    for(i=0; phrase->who[i]; i++){
        if(*dimrta % BLOQUE ==0){       //le guardo más espacio si lo necesita
           rta=realloc(rta, BLOQUE + *dimrta);
           *dimrta*=BLOQUE;
        }
        rta[*cantautores][i]=phrase->who[i];  //copio caracter por caracter
    }
    *cantautores++;
    creaRta(phrase->tailp, rta, dimrta, cantautores);
}

char ** authors(const wsiADT wsi, const char * category)
{  //uso searchCat para ver si existe dicha categoria, en el caso de q si copio en un vector de strings todos los autores

    int i, j,  flagc=0;
    tCat * catparametro;
    searchCat(wsi->primerc, category, &flagc, catparametro);
    if(flagc==1){                                //encontro la cateogria
        //voy a usar una funcion recursiva para recorrer la lista, e ir copiando uno por uno ya que los fui ordenando cuando los meti en la propia lista.
        char ** respuesta;
        int dim=0, cantautores=0;
        creaRta(catparametro->primerp, respuesta, &dim, &cantautores);
        return respuesta;
    }

    return NULL;
}

//el free y las funciones de iterador no se pedian completar.
marcelogarberoglio commented 1 year ago

No podés hacer int c= strcasecmp(cats->catname, name); if(cats==NULL

Ya que primero desreferenciás cats y después preguntás si es NULL. Si lo probás, vas a ver que aborta cuando quiere agregar la primer categoría

También está mal strcpy(nuevacat->catname, name); primero hay que reservar memoria

Traten de hacer una prueba, en el enunciado tienen el programa de testeo

O por ejemplo creaRta modifica una copia de respuesta. Cuando la función termina respuesta sigue valiendo basura. Una función no puede modificar una variable si no se le pasa su valor izquierdo

ThomasR62875 commented 1 year ago

Hola Marcelo, ahí me puse a ver las cosas que me corregiste. Cambie esas primeras lineas q estaban mal pero igualmente no logro que funcionen. Ahora estan así, y me sigue tirando sanitizer. Cual es el error dentro de strcasecmp?? (esquive unos assert para ver si las demas funciones andaban y tmb el error viene del strcasecmp) yo le paso dos vectores de chars en ambos lados, eso esta bien , verdad??

int c;
    if(cats==NULL || (c=strcasecmp(cats->catname, name))>0) 

Y lo último que me dijste, de la función creaRta fue una confusión mia, pero la intención era pasar el valor izquierdo. Con agregar otro asterico en el tipo de variable que recibe creaRta, pasar bien el "char * rta;" y poner ahora un adelante de rta cuando lo quiera usar dentro de esa función , ya estaria??

marcelogarberoglio commented 1 year ago

Las líneas que copiaste ahora están bien. Si compilaste con -g sanitizer te muestra cuál es la línea que arroja error. En todo caso pasá el código completo y cuál es el mensaje de error

En cuanto a creaRta podés pasar el puntero del puntero, pero me parece más simple que no sea void y retorne el nuevo puntero, por ejemplo como hace realloc, que le pasás el puntero actual y te devuelve el nuevo.

ThomasR62875 commented 1 year ago

Me di cuenta que en el comentarioa anterior me olvide de decirte que me estas saltando un sanitizer en el primer assert;


    wsiADT w = newWsi();
    char ** v = authors(w, "politica");
    assert(v[0]==NULL);     // no hay autores

Hice los cambios que me recomendaste en la función creaRta (tmb vi errores q tenia de antes) y quedo así:

char ** creaRta(Phrase * phrase, char ** rta,  int * dimrta, int * cantautores)
{   //copio el autor del nodo, y paso al proximo hasta llegar al final
    if(phrase==NULL){        //legue al final asiq corto
        return NULL;
    }
    int i;
    for(i=0; phrase->who[i]; i++){
        if(*dimrta % BLOQUE ==0){       //le guardo más espacio si lo necesita
            rta[*cantautores]=realloc(rta[*cantautores], BLOQUE + *dimrta);
        }
        rta[*cantautores][i]=phrase->who[i];  //copio caracter por caracter
        *dimrta+=1 ;
    }
    *cantautores++;
    *dimrta=0;
    rta= creaRta(phrase->tailp, rta, dimrta, cantautores);
    return rta;
}

char ** authors(wsiADT wsi, const char * category)
{  //uso searchCat para ver si existe dicha categoria, en el caso de q si copio en un vector de strings todos los autores

    int i, j,  flagc=0;
    tCat * catparametro;
    searchCat(wsi->primerc, category, &flagc, catparametro);
    if(flagc==1){                                //encontro la cateogria
        //voy a usar una funcion recursiva para recorrer la lista, e ir copiando uno por uno ya que los fui ordenando cuando los meti en la propia lista.
        char ** respuesta;
        int dim=0, cantautores=0;
        respuesta = creaRta(catparametro->primerp, respuesta, &dim, &cantautores);
        return respuesta;
    }

    return NULL;
}

Y sobre lo de strcasecmp, si lo estoy compilando con el -g sanitizer asiq te mando el código con el error: La primer funcion que usa el strcasecmp es :


tCat * addCatREC(tCat * cats, const char * name,  int *flag) {
    int c;
    if (cats == NULL || (c = strcasecmp(cats->catname, name)) >
                        0) { //pasaron una lista vacia, se llego al final o alfabeticamente ya se paso, asiq creo el nodo con la nueva info y lo devuelvo
        tCat *nuevacat = calloc(1, sizeof(tCat));
        cpystr(nuevacat->catname, name);
        nuevacat->tail = cats;
        return nuevacat;
    }
    if ((c = strcasecmp(cats->catname, name)) > 0) {
        tCat *nuevacat = calloc(1, sizeof(tCat));
        cpystr(nuevacat->catname, name);
        nuevacat->tail = cats;
        return nuevacat;
    }
    if (c == 0) {       //se encontro la cateogria asiq no debo agregar nada, solo activo el flag.
        *flag = 1;
        return cats;
    }
    //sigo buscando la cateogria.
    cats->tail= addCatREC(cats->tail, name, flag);
}

El error que salta sobre la linea del strcasecmp es este:

Captura de pantalla 2022-11-28 215743

marcelogarberoglio commented 1 year ago

Lo que dice el mensaje de error que aborta porque strcasecmp desreferencia un puntero NULL. Obivamente el error no está en strcasecmp sino en la llamada a la misma, en la línea 69, la función addCatRec. Eso es porque en catName dejás NULL cuando hacés cpystr(nuevacat->catname, name); no hay forma de que cpystr modifque la variable nuevacat->catname Por otro lado, en esa misma función no entiendo para que hacés el segundo if, si eso ya lo hiciste en el primer if, o sea: llamás a stracascmp pero ya sabemos que el resultado no va a ser mayor que cero

ThomasR62875 commented 1 year ago

Uh me estoy chocando siempre con la misma pared con lo de pasar el valor derecho como variable en vez del izquierdo, perdon. Lo del segundo if no te lo deberia haber mandado, fue un intento para ubicar mejor el error.

Cambie la función a una forma recursiva para ir copiadno el name letra por letra, y me quedo así,:


char * cpystr(char * recibe, const char * name, int *dim)
{   //es un strcpy q tmb guarda memoria en el heap
    if(name==NULL){
        return recibe;
    }
    if(*dim % BLOQUE == 0) {
        recibe = realloc(recibe, sizeof(char) * (*dim + BLOQUE +1));
    }
    recibe[*dim]=name[0];                                              //copia la primer letra del string name
    *dim++;                                                             //guarde una letra, asiq le sumo dim

    recibe= cpystr(recibe, name+1, dim);
    return recibe;
}

tCat * addCatREC(tCat * cats, const char * name,  int *flag) {
    int c;
    if (cats == NULL || (c = strcasecmp(cats->catname, name)) > 0) { //pasaron una lista vacia, se llego al final o alfabeticamente ya se paso, asiq creo el nodo con la nueva info y lo devuelvo
        tCat *nuevacat = calloc(1, sizeof(tCat));
        int dim=0;                                                      //dimensión usada en cpystr para saber cuando guardar más espacio
        nuevacat->catname = cpystr(nuevacat->catname, name, &dim);
        nuevacat->catname = realloc(nuevacat->catname, sizeof(char)*(dim+1));       //le reajusto la memoria q se le guardo
        nuevacat->tail = cats;
        return nuevacat;
    }

    if (c == 0) {       //se encontro la cateogria asiq no debo agregar nada, solo activo el flag.
        *flag = 1;
        return cats;
    }
    //sigo buscando la cateogria.
    cats->tail= addCatREC(cats->tail, name, flag);
}

Como en otro punto que te eh mandado por github salta el sanitizer en el if para saber si guardar más espacio if(*dim % BLOQUE == 0) la dim esta inicializada en 0 entonces nose porq una división hace saltar el sanitizer

marcelogarberoglio commented 1 year ago

¿Un copyStr recursivo? ¿Por qué te complicaste con eso? A mi me parece que el puntero name nunca se va a hacer NULL

ThomasR62875 commented 1 year ago

La verdad lo volvi a mirar más tranquilo y si, cambie todo inecesariamente. Con solo pasar el valor izquiero al cpystr anteriror ya estaria bien ?? quedaria así


void cpystr(char ** recibe, const char * name)
{   //es un strcpy q tmb guarda memoria en el heap
    int i;
    for(i=0; name[i]; i++){
        if(i%BLOQUE == 0){
            *recibe = realloc(*recibe, sizeof(char)*(BLOQUE+1+i));
        }
        *recibe[i]=name[i];
    }
    *recibe = realloc(*recibe, i+1);
    recibe[i]=0;        //el 0 final
}

tCat * addCatREC(tCat * cats, const char * name,  int *flag) {
    int c;
    if (cats == NULL || (c = strcasecmp(cats->catname, name)) > 0) { //pasaron una lista vacia, se llego al final o alfabeticamente ya se paso, asiq creo el nodo con la nueva info y lo devuelvo
        tCat *nuevacat = calloc(1, sizeof(tCat));
        cpystr(&nuevacat->catname, name);
        nuevacat->tail = cats;
        return nuevacat;
    }

    if (c == 0) {       //se encontro la cateogria asiq no debo agregar nada, solo activo el flag.
        *flag = 1;
        return cats;
    }
    //sigo buscando la cateogria.
    cats->tail= addCatREC(cats->tail, name, flag);
}
marcelogarberoglio commented 1 year ago

Seguís complicándote haciendo que copyStr sea void, no se por qué. Por ejemplo cuando hacés *recibe[i]=name[i]; tiene mayor precedencia el corchete que el asterisco Y acá usás recibe como si fuera un string, no un puntero a string recibe[i]=0;
Cuanto más complejo hagan el código, más probable que tengan errores.

ThomasR62875 commented 1 year ago

Buenas, segui intentando completar el codigo y me salto sanitizer en una linea dentro del searchCat. " encontro->catname = cats->catname; "

Pense que había sido q nunca le guarde memoria en el heap a ese string q iba a copiar (ademas de q así no se copia un string), asiq cambie la linea a " size_t dim; encontro->catname = cpystr(catnew, &dim); " pero también tira un sanitizer, y ahí ya me quede sin ideas de que puede ser el error.

void searchCat(tCat * cats, const char * catnew, int * flag, tCat * encontro)
{   //en el flag marca 1 si encontro la categoria, no lo cambia sino
    //si la encuentra iguala a esa categoria el nodo encontro.
    if(cats==NULL){         //llegue al final
        return;
    }

    if(strcasecmp(cats->catname, catnew)==0){                    //encontro la categortia, asiq la copio en el nuevo nodo, y corto la función
        encontro->catname = cats->catname;
        encontro->tail=cats->tail;
        encontro->primerp=cats->primerp;
        *flag=1;
        return;
    }

    if(cats->tail==NULL){                   //no encontro, y no hay más
        return;
    }
    //no encontro ni llego al fin paso a la proxima cat

    searchCat(cats->tail, catnew, flag, encontro);
}
marcelogarberoglio commented 1 year ago

Lo he mencionado más de una vez: no sé por qué se complican haciendo estas funciones void y pasando un puntero a la respuesta. Tal vez sea una nueva tendencia y yo me quedé en el pasado, pero haría que devuelva el valor que querés, sobre todo porque no todos los lenguajes permiten pasar un "valor izquierdo", así que la forma que copio abajo es fácilmente trasladable a otros lenguajes:

tCat searchCat(tCat cats, const char * catnew) {

if(cats==NULL){         //llegue al final
    return NULL;
}

// TODO faltaría retornar NULL si encuentra uno mayor al que está buscando

if(strcasecmp(cats->catname, catnew)==0){                    
    return cats;
}
return searchCat(cats->tail, catnew);

}

La forma en que vos lo hiciste es mucho más complicado, lo que te lleva a cometer errores importantes, como estar cambiando los tail: rompés la lista.