Questo sito utilizza cookies solo per scopi di autenticazione sul sito e nient'altro. Nessuna informazione personale viene tracciata. Leggi l'informativa sui cookies.
Username: Password: oppure
C/C++ - chiarimenti sulla funzione strtok
Forum - C/C++ - chiarimenti sulla funzione strtok

Pagine: [ 1 2 ] Precedente | Prossimo
Avatar
()
Newbie


Messaggi:
Iscritto:

Segnala al moderatore
Postato alle 1:00
Giovedì, 01/01/1970
salve, studiando la gestione delle stringhe in c mi sono imbattuto nella funzione strtok che suddivide il testo in token, nel manuale è specificato che solo per la prima chiamata si fornisce come argomento il puntatore alla stringhe da suddividere mentre le successive chiamate hanno bisogno di ricevere un puntatore NULL come argomento.
A parte il fatto che non riesco a capirne il perché... Ora sto lavorando a un programma complesso e ho bisogno di suddividere una stringa prima in tokens principali e poi in altri "sotto-tokens" per effettuare delle operazioni, la soluzione più immediata mi è sembrata quella di inserire due cicli for annidati come nell'esempio:
Codice sorgente - presumibilmente Plain Text

  1. for(tPtr=strtok(stringa, "separatore principale"); tPtr!=NULL; tPtr=strtok(NULL, "separatore principale")
  2.     for(stPtr=strtok(tPtr, "separatore minore"); stPtr!=NULL; stPtr=strtok(NULL, "separatore minore")


ma poi mi sono accorto che il tutto viene eseguito per un solo ciclo di quello esterno.
come posso ovviare? nel mio manuale questo caso non è trattato :-|

PM Quote
Avatar
nessuno (Normal User)
Guru^2


Messaggi: 6402
Iscritto: 03/01/2010

Segnala al moderatore
Postato alle 13:25
Lunedì, 15/08/2016
Non puoi usare così la strtok. Cosa ci devi fare con i token una volta ottenuti? È importante saperlo per vedere come operare al meglio... Fai anche un esempio concreto di stringhe da trattare.


Ricorda che nessuno è obbligato a risponderti e che nessuno è perfetto ...
---
Il grande studioso italiano Bruno de Finetti ( uno dei padri fondatori del moderno Calcolo delle probabilità ) chiamava il gioco del Lotto Tassa sulla stupidità.
PM Quote
Avatar
()
Newbie


Messaggi:
Iscritto:

Segnala al moderatore
Postato alle 17:22
Lunedì, 15/08/2016
In realtà ho elaborato già un'altra soluzione per la seconda suddivisione, purtroppo più macchinosa e sacrificando la riusabilità del codice, ma sono vicino anche a eliminare il secondo problema.
Avevo creato questa discussione per avere dei chiarimenti su questa funzione il quale funzionamento non mi è del tutto chiaro... Forse non sono stato chiaro prima.

PM Quote
Avatar
AldoBaldo (Member)
Guru


Messaggi: 699
Iscritto: 08/01/2015

Segnala al moderatore
Postato alle 13:05
Martedì, 16/08/2016
Premesso che è sempre bene leggere il caveat in calce a ciascuno dei miei messaggi, mi pare d'aver capito che strtok() conserva memoria (in qualche variabile statica sua interna) dell'operazione eseguita in seguito alla chiamata precedente e del punto della stringa in cui è arrivata la sua ultima analisi. Immagino quindi che "percepisca" che la nuova richiesta intende essere un seguito di quella precedente proprio verificando se il puntatore passato è o non è NULL. In caso di puntatore NULL riprende le operazioni da dove era rimasta, in caso di puntatore non NULL resetta le sue variabili statiche interne" e si predispone ad una nuova serie di operazioni.

Sto solo facendo delle ipotesi, nè! A stima...


ATTENZIONE! Sono un hobbista e l'affidabilità delle mie conoscenze informatiche è molto limitata. Non prendere come esempio il codice che scrivo, perché non ho alcuna formazione accademica e rischieresti di apprendere pratiche controproducenti.
PM Quote
Avatar
AldoBaldo (Member)
Guru


Messaggi: 699
Iscritto: 08/01/2015

Segnala al moderatore
Postato alle 15:50
Martedì, 16/08/2016
"Giusto per" (gran bella cosa le ferie!), m'è venuto il ghiribizzo di provare a fare una specie di "strtok() dei poveri" procedendo di testa mia.

Dal momento che mi ha sempre sconfifferato poco il fatto che la strtok() vera abbia questa specie di "persistenza", mi son detto: "la mia NON deve memorizzare alcun indice tra le chiamate". In più, giocherellando, mi sono accorto che la strtok() vera non ammette l'esistenza di elementi "vuoti", ovvero che se ci sono due terminatori adiacenti, l'elemento "vuoto" che ci si aspetterebbe di trovarci in mezzo viene omesso, saltato, ignorato... a me sembra un comportamento un po' strano.

Edit:: in più, ancora, strtok() modifica la stringa originale (infatti le si passa un char* e non un const char*) inzuppandola di terminatori.

Dunque, ho messo insieme Tuchinen(). Un particolare importante è che il nome della funzione si legge "Tuchinén", parola che significa "pezzettino". Mi sarebbe piaciuto anche chiamarla "strok!", come quando uno si becca una fregatura e... "STROK!", però l'assonanza sarebbe stata eccessiva e mi sarebbero magari state contestate questioni di copyright.

Donca, ciapa's tuchinén e lasla bùi, nuiùs d'in nuiùs! :k:

Codice sorgente - presumibilmente C++

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <string.h>
  4.  
  5. #define TIPO_ESEMPIO 1 // tra 0 e 6, per provare 7 situazioni diverse
  6.  
  7. #if TIPO_ESEMPIO == 0
  8. char  gStrEsempio[] = "primo tuchen|secondo tuchen|terzo tuchen|quarto tuchen";
  9. #elif TIPO_ESEMPIO == 1
  10. char  gStrEsempio[] = "primo tuchen|secondo tuchen|terzo tuchen||quinto tuchen";
  11. #elif TIPO_ESEMPIO == 2
  12. char  gStrEsempio[] = "primo tuchen|secondo tuchen|terzo tuchen||quinto tuchen|";
  13. #elif TIPO_ESEMPIO == 3
  14. char  gStrEsempio[] = "primo tuchen|secondo tuchen|terzo tuchen||quinto tuchen||";
  15. #elif TIPO_ESEMPIO == 4
  16. char  gStrEsempio[] = "|secondo tuchen|terzo tuchen||quinto tuchen||";
  17. #elif TIPO_ESEMPIO == 5
  18. char  gStrEsempio[] = "";
  19. #elif TIPO_ESEMPIO == 6
  20. char *gStrEsempio   = NULL;
  21. #endif // switch TIPO_ESEMPIO
  22.  
  23. /*==============================================================================
  24. Analizza la stringa C contenuta nell'array di caratteri che parte da "inizio" in
  25. cerca di uno qualsiasi tra i caratteri contenuti nella stringa C contenuta
  26. nell'array "sep". Appena trova la prima occorrenza di uno di quei caratteri ne
  27. memorizza il puntatore in "fine" e restituisce la quantita' dei caratteri
  28. compresi tra inizio (compreso) e fine (escluso).
  29. Se viene raggiunta la fine della stringa C contenuta nell'array "inizio" senza
  30. che sia stato trovato alcuno dei caratteri ricercati, in "fine" viene inserito
  31. un puntatore NULL.
  32. Se "inizio" e' un puntatore NULL, anche "fine" sara' un puntatore NULL e la
  33. funzione restituira' -1 (chiaramente una lunghezza non valida per qualsivoglia
  34. stringa).
  35. Se "inizio" punta a una stringa vuota, si considera comunque che contenga un
  36. elemento, perche' anche una stringa costituita dal solo terminatore e' comunque
  37. un elemento valido (una stringa lunga zero caratteri).
  38. ==============================================================================*/
  39.  
  40. int Tuchinen( const char *inizio, char **fine, const char *sep ) {
  41.     if( inizio )
  42.         return (*fine=strpbrk(inizio,sep)) ? *fine-inizio : strlen(inizio);
  43.     else { *fine = NULL; return -1; }
  44. }
  45.  
  46. /*==============================================================================
  47. Un programmino da intendere come esempio e come test.
  48. Cerca gli elementi contenuti nella stringa gStrEsempio (definita in piu'
  49. versioni in testa alla pagina) usando come separatore il solo carattere "|"
  50. (puo' essere interessante provare a usare due separatori contemporaneamente, ad
  51. esempio passando "| " o qualsiasi altra cosa).
  52. ==============================================================================*/
  53.  
  54. int main() {
  55.     char *inizio = NULL; // puntatore ausiliario
  56.     char *fine   = NULL; // puntatore ausiliario
  57.     int totToc   = 0;    // la quantita' degli elementi rilevati
  58.     int lToc     = 0;    // la lunghezza dell'elemento corrente
  59.     char aux     = '\0'; // carattere ausiliario
  60.  
  61.     inizio = gStrEsempio; // da dove cominciare?
  62.  
  63.     do {
  64.         // la chiamata alla funzione da provare
  65.         lToc = Tuchinen( inizio, &fine, "|" );
  66.  
  67.         if( lToc >= 0 ) { // se lToc fosse minore di zero, significherebbe
  68.                           // che non e' stato trovato alcun elemento valido
  69.  
  70.             // per poter stampare la stringa di lToc caratteri che parte da
  71.             // "inizio", occorre inserire TEMPORANEAMENTE un terminatore '\0'
  72.             // alla posizione inizio+lToc
  73.             aux = *(inizio+lToc);
  74.             *(inizio+lToc) = '\0';
  75.  
  76.             // visualizza un po' di informazioni
  77.             printf( "%4d. \"%s\" (%d caratteri)\n", ++totToc, inizio, lToc );
  78.  
  79.             // ripristina il carattere temporaneamente
  80.             // sostituito con il carattere terminatore '\0'
  81.             *(inizio+lToc) = aux;
  82.  
  83.             // il carattere puntato da "fine" e' un separatore;
  84.             // la nuova ricerca dovra' partire dal carattere successivo
  85.             inizio=fine+1; // per questo, "+1"
  86.         }
  87.         else {
  88.             // non sono ammessi puntatori NULL
  89.             printf( "Puntatore NULL, caprone!\n" );
  90.         }
  91.     } while( fine ); // se "fine" e' NULL vuol dire
  92.                      // che si e' in fondo alla stringa
  93.  
  94.     return 0;
  95. }



P.S. Per la cronaca, se tuchinén è un pezzettino, direi che dovrebbe essere ovvio che un tòc è un pezzo di medie dimensioni.

Ultima modifica effettuata da AldoBaldo il 16/08/2016 alle 16:19


ATTENZIONE! Sono un hobbista e l'affidabilità delle mie conoscenze informatiche è molto limitata. Non prendere come esempio il codice che scrivo, perché non ho alcuna formazione accademica e rischieresti di apprendere pratiche controproducenti.
PM Quote
Avatar
TheDarkJuster (Member)
Guru^2


Messaggi: 1620
Iscritto: 27/09/2013

Segnala al moderatore
Postato alle 16:11
Martedì, 16/08/2016
Io se dovessi fare qualcosa del genere farei una funzione ricorsiva che riempie un vettore

PM Quote
Avatar
AldoBaldo (Member)
Guru


Messaggi: 699
Iscritto: 08/01/2015

Segnala al moderatore
Postato alle 16:16
Martedì, 16/08/2016
Cioè? Un vettore di cosa?


ATTENZIONE! Sono un hobbista e l'affidabilità delle mie conoscenze informatiche è molto limitata. Non prendere come esempio il codice che scrivo, perché non ho alcuna formazione accademica e rischieresti di apprendere pratiche controproducenti.
PM Quote
Avatar
TheDarkJuster (Member)
Guru^2


Messaggi: 1620
Iscritto: 27/09/2013

Segnala al moderatore
Postato alle 16:18
Martedì, 16/08/2016
std::vector<std::string>

PM Quote
Avatar
AldoBaldo (Member)
Guru


Messaggi: 699
Iscritto: 08/01/2015

Segnala al moderatore
Postato alle 16:20
Martedì, 16/08/2016
Ah be', ma allora saresti in cpp e non in c...


ATTENZIONE! Sono un hobbista e l'affidabilità delle mie conoscenze informatiche è molto limitata. Non prendere come esempio il codice che scrivo, perché non ho alcuna formazione accademica e rischieresti di apprendere pratiche controproducenti.
PM Quote
Pagine: [ 1 2 ] Precedente | Prossimo