In C, per non usare strtok() (non perché non vada bene, solo per "speculazione"), ho trovato comodo predisporre una funzione estrai_elemento() con queste caratteristiche:
/*==============================================================================
PARAMETRI IN INGRESSO
const char *s la stringa dalla quale estrarre il primo elemento
eventualmente disponibile, individuato usando il
carattere sep come separatore tra gli elementi
(N.B. '\n' indica il punto dove termina la lettura
dei dati e NON DEVE mancare)
char sep il carattere che viene usato per riconoscere il punto
di separazione tra gli elementi contenuti nella stringa
passata in s
PARAMETRI IN USCITA
char **e in caso di successo dell'operazione, una copia
dell'elemento, in uno spazio di memoria allocato
dinamicamente con calloc(); spetta al chiamante
liberare la memoria eventualmente allocata
int *le in caso di successo dell'operazione, la lunghezza
dell'elemento copiato in *e
VALORE DI RITORNO
int un codice di errore che puo' assumere uno dei seguenti
valori...
0: elemento estratto correttamente
1: elemento estratto correttamente
e fine dei dati raggiunta
2: puntatore non valido tra i parametri
3: nessun dato nella stringa dei dati
4: new line mancante nella stringa dei dati
5: allocazione fallita
N.B. in caso di errore non viene allocata memoria dinamica,
per cui in caso di errore non si deve liberare nulla;
in caso di errore, *e e' NULL e *le e' -1
==============================================================================*/
int estrai_elemento( char **e, int *le, const char *s, char sep ) {
/*
se e e' valido, per prudenza preimposta *e su NULL
se tutti i parametri sono validi...
| se la stringa non e' vuota...
| | se la stringa contiene '\n'...
| | | trova la fine del primo elemento in s
| | | rileva la lunghezza dell'elemento trovato
| | | alloca memoria per una copia dell'elemento trovato
| | | se l'allocazione e' riuscita...
| | | | copia l'elemento trovato nello spazio di memoria allocato
| | | | segnala il puntatore alla copia in *e
| | | | segnala la lunghezza della copia in *le
| | | | restituisce 0 se ci sono altri elementi, 1 se e' l'ultimo
| | | ...se l'allocazione non e' riuscita, restituisce 5
| | ...se la stringa non contiene '\n', restituisce 4
| ...se la stringa e' vuota restituisce 3
...se ci sono puntatori non validi tra i parametri restituisce 2
*/
}
Nel mio programma di prova ho usato la funzione direttamente nel main(), così:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
const char kStr[] = "Uno|Due||Quattro|5\n";
char kSep = '|';
int estrai_elemento( char **e, int *le, const char *s, char sep ) {
// implementazione
}
int main() {
const char *pAux;
char *elemento;
int err, lElemento;
for( pAux=kStr, err=0; err<1; pAux += lElemento+1) {
err = estrai_elemento( &elemento, &lElemento, pAux, kSep );
printf( "%s\n", elemento );
free( elemento );
};
if( err > 1 ) printf( "Errore: %d\n\n", err );
return 0;
}
Sempre per speculazione fine a se stessa... rispetto a strtok(), usare una funzione "personalizzata" come quella che m'è venuta in mente può dare alcuni vantaggi, ad esempio...
- la possibilità di usare stringhe costanti
- di conseguenza, la possibilità di mantenere intatta la stringa passata
- la possibilità di rilevare campi vuoti (strtok() li salta?)
- la possibilità di trattare più stringhe "in parallelo" senza "interferenze"
Svantaggi che mi vengono in mente sono l'uso della memoria dinamica e (internamente, ad ogni chiamata) della funzione strrchr() per verificare la presenza del '\n'. Anche la necessità di aggiornare il puntatore ausiliario esternamente alla funzione potrebbe essere considerato uno scomodo orpello.
Trattandosi di codice amatoriale, la mia funzione è inoltre sicuramente meno efficiente di strtok() (e magari contiene pure degli errori).