Fòrum

[ C ] dubte amb structs i punters amb funcions

rotllan6.249 3 346👍 3.752
A veure si em podeu aclarir un problema. Crec que serà més fàcil si començo resumint el codi:

typdef struct {
char name[10];
int ob2;
etc.......
} est_t;

main() {
est_t *llista;
int numElem = loadElem(path, &llista);
.....
}

int loadElem(char *path, est_t **list) {
 /* Obro i llegeixo fitxer de text formatat, si fscanf quadra envio strings a funció /*
list = malloc(); -------> MALAMENT
int ok = checkElem(str1, str2.....  list[i]);
if (ok == 1) {
i++;
list = realloc(); -----> MALAMENT
}
........
}

int checkElem(char *str1......., est_t *dest) {
dest->ob2 = .............;
}

En resum: en iniciar el programa es carrega una llista de canals. Cada canal conté unes configuracions determinades, és a dir que per cada canal correcte guardat el fitxer de text s'ha de generar un est_t. Llavors s'han d'anar guardant en una taula dinàmica (no sé si hi haurà 3 canals guardats o 800 en el fitxer .txt). Tinc una altra funció que no he posat que és un cop funciona tot, per seleccionar un canal envio un string amb el nom i faig un recorregut buscant coincidencia amb llista[i]->name i em retorna l'index.

checkElem() funciona correctament.
Els errors són relacionats amb el punter llista/list i el malloc/realloc. Segons lo que poso em genera un segmention foult, o no em reté els valors quan retorna a main.
Coses que m'havien funcionat era retornar un est_t  o el punter (ara no ho recordo) i passar numElem com a argument per referència, però no m'agrada vull que la funció vagi aixís ja que també retorna -1 si hi ha errors.
També havia provat declarar est_t **llista; i em funcionava bé el malloc/realloc (ja no recordo ni com el tenia fet de tant que he remenat). En aquest cas em pensava que tot funcionava correctament, aparentment ho feia, però depurant altres coses em vaig adonar que després d'executar loadElem(), de sobte l'string de l'argv[0] es convertia en el mateix de llista[1].name.

Pel que he llegit en algun lloc això no em pot funcionar, segons un tutorial en anglès per fer una cosa similar a la que vull fer jo necessito:
est_t *llista;
est_t **p_llista;
Si és així vaig més perdut del que em pensava i si a més ho he de fer passant-ho per funcions encara més...
A veure si algú m'ho pot aclarir una mica.

Respostes

Configuració
  • Calçot Marxista791 2👍 1.019
    Si he entès bé vols una "taula" (array?) i ho vols generar a una funció a part, passant per referència...

    Llavors potser et cal:

    *list = malloc();

    a loadElem (i el mateix pel realloc entenc)
  • rotllan6.249 3 346👍 3.752
    Per cert, comentar que he provat, sabent que tinc dos canals al fitxer (comentant realloc):

    *list = malloc(2* sizeof (est_t*));
    list[0] = malloc(sizeof (est_t));
    list[1] = malloc(sizeof (est_t));

    Això no em peta però quan torno a main, llista[0] és correcta, manté els valors assignats, però llista[1] ja no.
    EDITO: de fet ja no m'agafa correctament ni list[1] a la funció, abans de retornar a main. A més *list és el mateix que list[0] no?
    I si faig *list = malloc(2* sizeof (est_t)); tampoc m'agafa el segon.


    TORNO A EDITAR:
    he dit malament, havia eliminat un canal. Ara amb dos canals: fent els 3 mallocs sí que perd el segon canal quan retorna a main (a la funció el reté). En retornar el netbeans em diu: cannot subscribe requested type.
    Fent *list = malloc(2* sizeof (est_t)); peta.
  • enriquito8.900 13 248👍 487
    és culpa del camel case

    si fessis servir guionets baixos, tot funcionaria bé
  • enriquito8.900 13 248👍 487
    .

    (després m'ho miro)
  • analista67 1👍 57
    El que has passat no queda molt clar, però veig algunes coses importants:
     * No pots utilitzar malloc() per afegir un element a la llista ja que et carregaries el que ja hi havia.
     * Et falta passar el nombre d'elements actuals a la llista per tal de que que puguis afegir el nou element al final i passar a realloc() la nova mida.
     * Com que utilitzaràs realloc(), cal que li passis un argument d'un buffer. Si inicialitzes llista a NULL, la primera crida actuarà com a malloc() i les següents estendràn l'àrea reservada.

    int loadElem(char *path, est_t **list, size_t list_count)
    {
        *list=realloc(list, sizeof(**list)*(list_count+1));
        strcpy((*list)[list_count].name, ...);//XXX cal comprovar anteriorment la mida del que es vol posar per evitar un buffer overflow
        //...
        return ++list_count;
    }
    • analista67 1👍 57
      Ara me n'adono que el primer argument de realloc hauria de ser *list:

      int loadElem(char *path, est_t **list, size_t list_count)
      {
          *list=realloc(*list, sizeof(**list)*(list_count+1));
          strcpy((*list)[list_count].name, ...);//XXX cal comprovar anteriorment la mida del que es vol posar per evitar un buffer overflow
          //...
          return ++list_count;
      }

      En realitat, jo hauria utilitzat el prototip
      est_t* loadElem(char* path, est_t* list, size_t list_count)
      ja que el codi queda més net.
      • rotllan6.249 3 346👍 3.752
        però quan crido la funció perquè li passaria list_count? di de cas seris una variable local de la funció no? perquè list_count va augmentant segons vagi obtenint canals vàlids del fitxer.
        La idea era passar una taula dinàmica d'structs (per referència per mantenir-la un cop retorni) i que em retornés el número d'elements (structs).
        Ara també he pensat que podria declarar est_t *llista; com a extern a la capçalera del fitxer de les funcions (tinc diversos fitxers de fonts i capçaleres) en comptes de passar-ho com argument, potser també em facilitaria la vida, ja que si ho perdo en retornar de la funció, entenc que ja no ho perdria.
    • rotllan6.249 3 346👍 3.752
      mes amunt he posat un missatge amb algunes peoves de malloc que havia fet. Al vespre quan vagi a casa m'hi tornaré a posar.
  • radi2catUsuari sumador37.988 12 15👍 14.322
    Pero quins parametres passes a malloc i realloc, d'on surten str1 i str2, que fas a checkElem, falta molta informacio.
    • rotllan6.249 3 346👍 3.752
      malloc i realloc he provat moltes coses, algunes ho he posat a l'altre missatge. La resta no ho he posat pq he pensat que no era rellevant, ja ho je explicat en el comentari, simplement obro un fitxer amb el camí que li passo a la funció, llegeixo caràcters fins que trobo { i faig fscanf de diverses coses. de fet ho guardo a una estructura que seria struct estInput, que és en realitat el que passo a la funció chek, més que res per simplificar el prototip de funció. Si char c amb fscanf es } vol dir que el format estava be, pero falta revisar els valors i posar-los si son valids en tipus de dades adequats, per exemple "fm" s'ha de comvertir al tipus mode_t que es un enum, que es el que em demana la funcio setModeRequest(), per això passo per referència l'struct. la idea era que si tinc una taula d'structs amb la validacio ja queda guardat a lloc. si retorna valid faig realloc per poder-ne afegir un altre i invremento index. si no es valid no faig res i el següent ja el matxacarà.

      Però tot això ja funciona i he pensat que seria posar codi superflu per resoldre el problema, igual que he simplificat el contingut de structs i canviat alguns noms per fer-ho entenedor en aquest context.
  • paleta3.050 1 638👍 3.424
    El meu consell ja el saps, es pot resumir en tres caràcters:

    C++ 

    Abraça el llenguatge dels Déus, i alliberat dels mallocs, callocs, reallocs, frees, strdups... i altres funcions infernals.
  • rotllan6.249 3 346👍 3.752
    Pas a pas. Jo vinc de l'electricitat. Vaig començar amb lògica de contactes i contactors, vaig saltar a programar PLCs a nivell de bits en ladder, després PLCs amb registres i jugar una mica amb llista d'instruccions, i finalment C. Quan ho domini més potser serà el moment de saltar a C++.
  • rotllan6.249 3 346👍 3.752
    SOLUCIÓ ALTERNATIVA:

    A veure acabo de provar declarant list com a variable global i funciona.
    tinc diversos fitxer de codi, ho resumiré diguent que tinc main.c main.h i func.c func.h

    He declarat:
    extern est_t *list; a func.h
    est_t *list; a func.c
    obviament he elimiant est_t **list dels prototips i les crides.

    a loadElem inicialitzo:
    list = (est_t *) calloc(1, sizeof (est_t));
    com que el checkElem demana un punter el crido així:
    int ok = checkChannel(chan, &list[i]); (ampersand, que me'l feia treure de l'altra manera).
    finalment si el canal és valid faig realloc:
    list = (est_t *) realloc(list, ((i + 1) * sizeof (est_t)));

    I llestos ja funciona. De fet això ja em funcionava, ja que és molt semblat al que ja tenia fet a unes funcions per treballar amb fitxers CSV en un altre apartat del programa, però en aquell cas no ho necessito fora de la funció.
    En aquest cas el problema em ve a l'hora de passar-ho al main i sobretot passar per referència, si fos al revés, generar-ho al main i passar-ho per valor a la funció, suposo que no hauria tingut problemes.

    Pel que fa al programa, puc deixar la variable extern, funciona, no és com ho volia però suposo que és correcte. Llavors també penso que potser si tinc la llista en una variable global, també podria guardar el numElements en una altra variable global. Aquí no tinc prou coneixements per jutjar quin codi és més elegant, en tot cas si ho fes podria retornar 0 o 1 per si hi ha hagut errors.
    Jo penso que totes les variables del programa millor tenirles locals a main, o almenys a main.c i que siguin accessibles només a les funcions de main.c que a més les tinc static.

    De totes maneres continuo amb el dubte de com passar una taula dinàmica d'structs per referència.

  • Publicitat

    Novetats

    Fòrums

    • 8.905.886 missatges
    • 207.991 temes
    Fixa la barra dreta
    Accedeix als fòrums Normes dels fòrums

    Fils
    més votats

    Accedeix als fils més votats
    Publicitat