Repository 32bit  Forum
Repository 64bit  Wiki

[C] Problema con strtok

Forum dedicato alla programmazione.

Moderatore: Staff

Regole del forum
1) Citare in modo preciso il linguaggio di programmazione usato.
2) Se possibile portare un esempio del risultato atteso.
3) Leggere attentamente le risposte ricevute.
4) Scrivere i messaggi con il colore di default, evitare altri colori.
5) Scrivere in Italiano o in Inglese, se possibile grammaticalmente corretto, evitate stili di scrittura poco chiari, quindi nessuna abbreviazione tipo telegramma o scrittura stile SMS o CHAT.
6) Appena registrati è consigliato presentarsi nel forum dedicato.

La non osservanza delle regole porta a provvedimenti di vari tipo da parte dello staff, in particolare la non osservanza della regola 5 porta alla cancellazione del post e alla segnalazione dell'utente. In caso di recidività l'utente rischia il ban temporaneo.

[C] Problema con strtok

Messaggioda elvis » mar feb 01, 2011 13:23

Salve, all'interno di un programma (che non ricopio per intero) ad un certo punto ho bisogno di una funzione che mi prenda una stringa e me la suddivida in un vettore di stringhe (vettore di dimensione N nota).
La stringa ha questo formato: "testo0#testo1#...#testoN-1#. Potrebbe però anche non avere del testo tra un # e un altro. (esempio: "asd#rotfl#lol##qwerty#asd##fine#" ).

Il formato mi ha subito fatto pensare all'uso di strtok, il problema però è che se incontra il "testo nullo" da quanto ho capito strtok va avanti a cercare un prossimo carattere buono per assegnarlo al prossimo token, mentre io avrei bisogno che quel testo vuoto corrisponda ad un puntatore NULL nella cella corrispondente del vettore .

Per farmi capire meglio, se la stringa è "asd##fine# il vettore di stringhe che mi serve è questo:

v[0] = "asd"
v[1] = NULL
v[2] = "fine"

mentre invece strtok mi "taglia" il token contenente il testo nullo, e alla fine ho:

v[0] = "asd"
v[1] = "fine"

Il pezzo di codice incriminato è questo:

Codice: Seleziona tutto
char **array_answer(char *answ, int N)    // Funzione che suddivide la stringa answ in un vettore di sottostringhe
{
   int i;
 
   char *temp = malloc(strlen(answ)*sizeof(char));  // Alloca memoria per una copia di answ
   
   char *cpy = strcpy(temp, answ);   // copia answ nella memoria appena allocata
   
   char *buffer;  // variabile per allocare memoria per ogni sottostringa di answ
   
   char **risposte = malloc(N*sizeof(char *));  // vettore di stringhe che conterrà i vari token di answ
   
   char *token = strtok(cpy, "#");  // Comincia a dividere la copia di answ
   
   for (i = 0; token != NULL; i++) {  // Iterazione per memorizzare tutti i token nel vettore di stringhe
     
      if (strlen(token) > 0) {  // se il token contiene del testo...
   
    buffer = malloc(strlen(token)*sizeof(char));  // alloca memoria per ogni token
 
    risposte[i] = strcpy(buffer, token);   // memorizza ogni token nel vettore
      }
     
      if (strlen(token) == 0) risposte[i] = NULL;

      printf("risposte[%d ] =  %s \n", i,  risposte[i]);  // stampa di prova

      token = strtok(NULL, "#");  // continua a dividere la copia di asnw
   }   

   return risposte;   
}


Qualche idea? Oppure non ne esco e devo trovare qualche alternativa all'uso di strtok?
elvis
Linux 1.0
Linux 1.0
 
Messaggi: 53
Iscritto il: lun set 27, 2010 9:35
Slackware: 13.1 x64
Desktop: KDE 4.5.2
Distribuzione: Opensuse 11.3 x86

Re: [C] Problema con strtok

Messaggioda RedSkull92 » mar feb 01, 2011 15:05

nelle malloc non dovresti fare il cast ?
Avatar utente
RedSkull92
Linux 2.6
Linux 2.6
 
Messaggi: 553
Iscritto il: mar apr 21, 2009 16:25
Località: Palermo
Slackware: 64bit -current
Kernel: 3.5.4
Desktop: FluxBox

Re: [C] Problema con strtok

Messaggioda elvis » mar feb 01, 2011 15:43

Che io sappia con malloc il casting in C è automatico, nel caso di tipi standard, mentre è consigliato nel caso di tipi derivati (per esempio se si alloca per una struttura o una lista). In ogni caso non penso sia questo la fonte del problema, o mi sbaglio? Pensi che possa influire?
elvis
Linux 1.0
Linux 1.0
 
Messaggi: 53
Iscritto il: lun set 27, 2010 9:35
Slackware: 13.1 x64
Desktop: KDE 4.5.2
Distribuzione: Opensuse 11.3 x86

Re: [C] Problema con strtok

Messaggioda targzeta » mar feb 01, 2011 17:53

Beh, direi che il man non ti lascia scampo, con strtok(3) non si può fare. Eccoti un'alternativa:
Codice: Seleziona tutto
#include <stdio.h>  /* printf() */
#include <string.h> /* strlen(), strncpy(), etc.. */
#include <stdlib.h> /* malloc(), realloc() and free() */

char **array_answer(char *, int *);

int main()
{
  char **result;
  int num_result, i;

  result = array_answer("#casa#nonna##pollo", &num_result);

  for ( i = 0; i < num_result; i++ )
    printf("%s\n", ( result[i] ) ? result[i] : "NULL");

  /* Free allocated memory */
  for ( i = 0; i < num_result; i++ )
    if ( result[i] )
      free(result[i]);
  free(result);

  return 0;
}

char **array_answer(char *answ, int *founds)
{
  char **risposte, *tmp;
  int risp_alloc, i;

  risp_alloc = 2; /* dimensione iniziale dell'array risposte */
  risposte = malloc(risp_alloc * sizeof(char *));

  for ( *founds = 0, tmp = answ; tmp <= answ + strlen(answ); tmp += i+1, (*founds)++ )
    {
      i = strcspn(tmp, "#");

      if ( *founds == risp_alloc )
        risposte = realloc(risposte, (risp_alloc *= 2) * sizeof(char *));

      if ( i > 0 )
        {
          risposte[*founds] = malloc(i + 1);
          strncpy(risposte[*founds], tmp, i);
          risposte[*founds + 1] = '\0';
        }
      else
        risposte[*founds] = NULL;
    }

  return risposte;
}
Alcune note:
  • l'allocazione dell'array risposte è dinamica e incrementale, io sono partito da un minimo di 2, ma è meglio partire da un valore più ragionevole per minimizzare le realloc(3). Ho notato che nel tuo prototipo usi il valore N, però in linea teorica non si sa quanto quando sarà questo N.
  • La funzione tiene ovviamente conto anche dei delimitatori inseriti all'inizio e alla fine, con un po' di fantasia si può facilmente evitare questi due casi.
  • Dato che il delimitatore è un singolo carattere, forse sarebbe meglio utilizzare un algoritmo che sfrutti questo fatto, piuttosto che utilizzare una funzione come strcspn(3) che cerca stringhe. Magari si può sfruttare la funzione index(3).
  • Se al punto precedente si vuole modificare il delimitatore per farlo diventare qualcosa di più grande che di un singolo byte, allora nel for, il 'tmp += i+1' diventa 'tmp += i+strlen(delimitatore)',
  • Vale la pena notare anche il no memory leak, grazie alle free(3) nel main.
  • Ovviamente le s.c. andrebbero controllate (vedi malloc e realloc)

Emanuele
Linux Registered User #454438
Se pensi di essere troppo piccolo per fare la differenza, prova a dormire con una zanzara -- Dalai Lama
20/04/2013 - Io volevo Rodotà
Avatar utente
targzeta
Iper Master
Iper Master
 
Messaggi: 6176
Iscritto il: gio nov 03, 2005 14:05
Località: Carpignano Sal. (LE) <-> Pisa
Nome Cognome: Emanuele Tomasi
Slackware: current
Kernel: latest stable
Desktop: IceWM

Re: [C] Problema con strtok

Messaggioda elvis » gio feb 03, 2011 16:35

Ti ringrazio, appena ho una mezz'ora libera mi ci metto.
elvis
Linux 1.0
Linux 1.0
 
Messaggi: 53
Iscritto il: lun set 27, 2010 9:35
Slackware: 13.1 x64
Desktop: KDE 4.5.2
Distribuzione: Opensuse 11.3 x86

Re: [C] Problema con strtok

Messaggioda elvis » dom feb 06, 2011 13:20

spina ha scritto:Alcune note:
  • l'allocazione dell'array risposte è dinamica e incrementale, io sono partito da un minimo di 2, ma è meglio partire da un valore più ragionevole per minimizzare le realloc(3). Ho notato che nel tuo prototipo usi il valore N, però in linea teorica non si sa quanto quando sarà questo N.
  • La funzione tiene ovviamente conto anche dei delimitatori inseriti all'inizio e alla fine, con un po' di fantasia si può facilmente evitare questi due casi.
  • Dato che il delimitatore è un singolo carattere, forse sarebbe meglio utilizzare un algoritmo che sfrutti questo fatto, piuttosto che utilizzare una funzione come strcspn(3) che cerca stringhe. Magari si può sfruttare la funzione index(3).
  • Se al punto precedente si vuole modificare il delimitatore per farlo diventare qualcosa di più grande che di un singolo byte, allora nel for, il 'tmp += i+1' diventa 'tmp += i+strlen(delimitatore)',
  • Vale la pena notare anche il no memory leak, grazie alle free(3) nel main.
  • Ovviamente le s.c. andrebbero controllate (vedi malloc e realloc)

Emanuele

Allora, la funzione che mi hai suggerito va bene, però ho alcune perplessità. Preciso innanzitutto che la stringa da spezzare non ha il delimitatore iniziale # come carattere più a sinistra, mentre mi pare di aver capito che tu pensassi che lo avesse (anche se ripeto, non ci sono problemi nell'esecuzione del programma).

-Detto ciò, la dimensione del vettore di stringhe è sicuramente N, che mi è noto, per cui le realloc sono proprio necessarie?
-Anche quel *founds mi lascia qualche dubbio, praticamente tu lo inizializzi a 0 e lo incrementi fino a quando tmp non punta all'ultimo carattere di answ; però se non sbaglio con questa inizializzazione si va a sovrascrivere il valore di N nello stack della funzione chiamante (poichè chiamo la funzione array_answer con &N come secondo parametro) e se per qualche malaugurato inconveniente il for principale dovesse interrompersi (per esempio, un allocazione fallita) perderei anche il valore N stesso.
-La funzione index sarebbe...? Non riesco a trovarla da nessuna parte..
-strcspn non restituisce un puntatore a char? Come mai il compilatore non dà errore se la chiamo come hai fatto tu (cioè come se fosse una funzione void che non ritorna nulla) ?

Comunque ti ringrazio di nuovo!
elvis
Linux 1.0
Linux 1.0
 
Messaggi: 53
Iscritto il: lun set 27, 2010 9:35
Slackware: 13.1 x64
Desktop: KDE 4.5.2
Distribuzione: Opensuse 11.3 x86

Re: [C] Problema con strtok

Messaggioda targzeta » dom feb 06, 2011 17:27

elvis ha scritto:-Detto ciò, la dimensione del vettore di stringhe è sicuramente N, che mi è noto, per cui le realloc sono proprio necessarie?
No, non sono assolutamente necessarie, anzi, le puoi (dovresti) evitare.

elvis ha scritto:-Anche quel *founds mi lascia qualche dubbio, praticamente tu lo inizializzi a 0 e lo incrementi fino a quando tmp non punta all'ultimo carattere di answ; però se non sbaglio con questa inizializzazione si va a sovrascrivere il valore di N nello stack della funzione chiamante (poichè chiamo la funzione array_answer con &N come secondo parametro) e se per qualche malaugurato inconveniente il for principale dovesse interrompersi (per esempio, un allocazione fallita) perderei anche il valore N stesso.
Il prototipo della funzione vuole un puntatore ad intero, vuol dire che quando modifico *founds, io modifico il contenuto della locazione di memoria a cui punta il parametro che mi è stato passato. In pratica quello che mi viene passato non ha nessuna importanza, per me quello non è N.

elvis ha scritto:-La funzione index sarebbe...? Non riesco a trovarla da nessuna parte..
man 3 index
Codice: Seleziona tutto
 char *index(const char *s, int c);
       The  index()  function  returns a pointer to the first occurrence of the
       character c in the string s.


elvis ha scritto:-strcspn non restituisce un puntatore a char? Come mai il compilatore non dà errore se la chiamo come hai fatto tu (cioè come se fosse una funzione void che non ritorna nulla) ?
man 3 strcspn
Codice: Seleziona tutto
size_t strspn(const char *s, const char *accept);
come vedi non ritorna un puntatore a carattere.

Emanuele
Linux Registered User #454438
Se pensi di essere troppo piccolo per fare la differenza, prova a dormire con una zanzara -- Dalai Lama
20/04/2013 - Io volevo Rodotà
Avatar utente
targzeta
Iper Master
Iper Master
 
Messaggi: 6176
Iscritto il: gio nov 03, 2005 14:05
Località: Carpignano Sal. (LE) <-> Pisa
Nome Cognome: Emanuele Tomasi
Slackware: current
Kernel: latest stable
Desktop: IceWM

Re: [C] Problema con strtok

Messaggioda elvis » mar feb 08, 2011 13:35

spina ha scritto:
man 3 index
Codice: Seleziona tutto
 char *index(const char *s, int c);
       The  index()  function  returns a pointer to the first occurrence of the
       character c in the string s.

Ok capito, posso chiederti dove la trovo questa funzione? Non c'è nè sul Deitel nè sul Kernighan nè la trovo in rete : D

man 3 strcspn
Codice: Seleziona tutto
size_t strspn(const char *s, const char *accept);

come vedi non ritorna un puntatore a carattere.

Perdonami, non intendevo strcspn bensì strncpy, che ritorna il puntatore alla stringa contenente la copia appena effettuata, ma a quanto pare si può chiamare come se fosse una f. che ritorna void, giusto?

Ultimissima curiosità, posso chiederti cosa intendi con man 3? Ho visto poi che questo 3 lo metti anche nel corpo delle funzioni (esempio, malloc(3), ecc.).
elvis
Linux 1.0
Linux 1.0
 
Messaggi: 53
Iscritto il: lun set 27, 2010 9:35
Slackware: 13.1 x64
Desktop: KDE 4.5.2
Distribuzione: Opensuse 11.3 x86

Re: [C] Problema con strtok

Messaggioda Mario Vanoni » mar feb 08, 2011 15:57

elvis ha scritto:Ultimissima curiosità, posso chiederti cosa intendi con man 3? Ho visto poi che questo 3 lo metti anche nel corpo delle funzioni (esempio, malloc(3), ecc.).

Il mondo UNIX ha 8 capitoli di manuale,
1, 2, 3, 4, 5, 6, 7 e 8, suddivisi in campi di interesse.

P.e esiste un kill(1) come pure un kill(2),
il primo per utenti, il secondo per programmazione a livello HW.

Mettendo man 1 kill oppure man 2 kill trovi subito quello cercato.

Non so come hai impostato il tuo man(1), se digito
man 3 index
mi ritorna
Codice: Seleziona tutto
INDEX(3)                                                                           Linux Programmer's Manual                                                                          INDEX(3)



NAME
       index, rindex - locate character in string

SYNOPSIS
       #include <strings.h>

       char *index(const char *s, int c);

       char *rindex(const char *s, int c);

DESCRIPTION
       The index() function returns a pointer to the first occurrence of the character c in the string s.

       The rindex() function returns a pointer to the last occurrence of the character c in the string s.

       The terminating NULL character is considered to be a part of the strings.

RETURN VALUE
       The index() and rindex() functions return a pointer to the matched character or NULL if the character is not found.

CONFORMING TO
       4.3BSD; marked as LEGACY in POSIX.1-2001.  POSIX.1-2008 removes the specifications of index() and rindex().

SEE ALSO
       memchr(3), strchr(3), strpbrk(3), strrchr(3), strsep(3), strspn(3), strstr(3), strtok(3)

COLOPHON
       This  page  is part of release 3.15 of the Linux man-pages project.  A description of the project, and information about reporting bugs, can be found at http://www.kernel.org/doc/man-
       pages/.



GNU                                                                                       2008-08-06                                                                                  INDEX(3)



EDIT: vedi anche man 7 man-pages
Mario Vanoni
Iper Master
Iper Master
 
Messaggi: 3174
Iscritto il: lun set 03, 2007 20:20
Località: Cuasso al Monte (VA)
Nome Cognome: Mario Vanoni
Slackware: 12.2
Kernel: 3.0.4 statico
Desktop: fluxbox/seamonkey

Re: [C] Problema con strtok

Messaggioda targzeta » mar feb 08, 2011 16:17

elvis ha scritto:
man 3 strcspn
Codice: Seleziona tutto
size_t strspn(const char *s, const char *accept);

come vedi non ritorna un puntatore a carattere.

Perdonami, non intendevo strcspn bensì strncpy, che ritorna il puntatore alla stringa contenente la copia appena effettuata, ma a quanto pare si può chiamare come se fosse una f. che ritorna void, giusto?
Semplicemente io ignoro il valore di ritorno, che in questo caso è lo stesso di quello che gli passo io. Non la sto invocando come se fosse una funzione void, sto solo ignorando il valore di ritorno.

Per il resto ti ha risposto Mario,
Emanuele

P.S.
Mario Vanoni ha scritto:...
P.e esiste un kill(1) come pure un kill(2),
il primo per utenti, il secondo per programmazione a livello HW.
Programmazione a livello HW?
Linux Registered User #454438
Se pensi di essere troppo piccolo per fare la differenza, prova a dormire con una zanzara -- Dalai Lama
20/04/2013 - Io volevo Rodotà
Avatar utente
targzeta
Iper Master
Iper Master
 
Messaggi: 6176
Iscritto il: gio nov 03, 2005 14:05
Località: Carpignano Sal. (LE) <-> Pisa
Nome Cognome: Emanuele Tomasi
Slackware: current
Kernel: latest stable
Desktop: IceWM

Re: [C] Problema con strtok

Messaggioda Mario Vanoni » mar feb 08, 2011 16:27

spina ha scritto:P.S.
Mario Vanoni ha scritto:...
P.e esiste un kill(1) come pure un kill(2),
il primo per utenti, il secondo per programmazione a livello HW.
Programmazione a livello HW?

Sorry, falsa interpretazione di
Codice: Seleziona tutto
 2 System calls
                 Those functions which must be performed by the kernel.

Ai tempi, essendo i kernel proprietari, agivano direttamente sulla HW.
Mario Vanoni
Iper Master
Iper Master
 
Messaggi: 3174
Iscritto il: lun set 03, 2007 20:20
Località: Cuasso al Monte (VA)
Nome Cognome: Mario Vanoni
Slackware: 12.2
Kernel: 3.0.4 statico
Desktop: fluxbox/seamonkey

Re: [C] Problema con strtok

Messaggioda elvis » mar feb 08, 2011 21:11

@ Mario: perfetto, grazie. Mi si è aperto un mondo : D

@ spina: chiaro, non ci avevo proprio pensato. Grazie di tutto ancora.
elvis
Linux 1.0
Linux 1.0
 
Messaggi: 53
Iscritto il: lun set 27, 2010 9:35
Slackware: 13.1 x64
Desktop: KDE 4.5.2
Distribuzione: Opensuse 11.3 x86


Torna a Programmazione

Chi c’è in linea

Visitano il forum: Nessuno e 3 ospiti