¿Cómo escribo una función para dividir y devolver una matriz para una cadena con delimitadores en el lenguaje de programación C?
char* str = "JAN,FEB,MAR,APR,MAY,JUN,JUL,AUG,SEP,OCT,NOV,DEC";
str_split(str,',');
namco
¿Cómo escribo una función para dividir y devolver una matriz para una cadena con delimitadores en el lenguaje de programación C?
char* str = "JAN,FEB,MAR,APR,MAY,JUN,JUL,AUG,SEP,OCT,NOV,DEC";
str_split(str,',');
tyler
pienso strsep
sigue siendo la mejor herramienta para esto:
while ((token = strsep(&str, ","))) my_fn(token);
Esa es literalmente una línea que divide una cadena.
Los paréntesis adicionales son un elemento estilístico para indicar que estamos probando intencionalmente el resultado de una asignación, no un operador de igualdad. ==
.
Para que ese patrón funcione, token
y str
ambos tienen tipo char *
. Si comenzó con un literal de cadena, primero querrá hacer una copia:
// More general pattern:
const char *my_str_literal = "JAN,FEB,MAR";
char *token, *str, *tofree;
tofree = str = strdup(my_str_literal); // We own str's memory now.
while ((token = strsep(&str, ","))) my_fn(token);
free(tofree);
Si dos delimitadores aparecen juntos en str
obtendrás un token
valor que es la cadena vacía. El valor de str
se modifica en el sentido de que cada delimitador encontrado se sobrescribe con un byte cero, otra buena razón para copiar primero la cadena que se analiza.
En un comentario, alguien sugirió que strtok
es mejor que strsep
porque strtok
es más portátil. Ubuntu y Mac OS X tienen strsep
; es seguro suponer que otros sistemas unixy también lo hacen. Windows carece strsep
pero tiene strbrk
que permite este corto y dulce strsep
reemplazo:
char *strsep(char **stringp, const char *delim) {
if (*stringp == NULL) { return NULL; }
char *token_start = *stringp;
*stringp = strpbrk(token_start, delim);
if (*stringp) {
**stringp = '\0';
(*stringp)++;
}
return token_start;
}
Aquí hay una buena explicación de strsep
contra strtok
. Los pros y los contras pueden juzgarse subjetivamente; sin embargo, creo que es una señal reveladora de que strsep
fue diseñado como un reemplazo para strtok
.
Más precisamente sobre la portabilidad: es no POSIX 7pero derivado de BSD e implementado en glibc.
– Ciro Santilli Путлер Капут 六四事
20 de julio de 2015 a las 7:04
Estaba a punto de preguntar… El C de Pelle tiene strdup(), pero no strsep().
– rdtsc
3 de febrero de 2017 a las 2:18
por qué tofree
es el que está libre y no str
?
– Sdlion
17 mayo 2018 a las 17:20
no puedes liberar str
porque su valor se puede cambiar mediante llamadas a strsep()
. El valor de tofree
apunta constantemente al inicio de la memoria que desea liberar.
– Tyler
18 mayo 2018 a las 18:10
saif mahmud
Traté de hacer uno muy simple. También estoy mostrando un ejemplo en main().
#include <stdio.h>
#include <string.h>
void split(char* inputArr, char** outputArr, char* delim) {
char *temp;
temp = strtok(inputArr, delim);
for(int i = 0; temp != NULL; i++) {
outputArr[i] = temp;
temp = strtok(NULL, " ");
}
}
int main(int argc, char **argv){
/* check for proper arguments */
if(argc != 2){
printf("One Argument Expected\n");
} else {
printf("\n");
/*---------main code starts here----------*/
FILE * myScriptFile;
myScriptFile = fopen(argv[1], "r");
/* read txt file and split into array like java split() */
int bufferLen = 100;
char buffer[bufferLen];
char *splitArr[100];
while(fgets(buffer, bufferLen, myScriptFile) != NULL){
split(buffer, splitArr, " ");
printf("Index 0 String: %s\n", splitArr[0]);
printf("Index 1 String: %s\n", splitArr[1]);
printf("Index 2 String: %s\n", splitArr[2]);
printf("Index 3 String: %s\n", splitArr[3]);
}
fclose(myScriptFile);
}
printf("\nProgram-Script Ended\n");
return 0;
}
Suponga que un archivo .txt tiene
Hello this is test
Hello2 this is test2
ejecutarlo con un archivo .txt como parámetro daría
Index 0 String: Hello
Index 1 String: this
Index 2 String: is
Index 3 String: test
Index 0 String: Hello2
Index 1 String: this
Index 2 String: is
Index 3 String: test2
Ambas cosas strtok()
y strsep()
modificar la cadena de entrada. Podemos escribir una función para dividir la cadena en función de los delimitadores usando strspn() y strpbrk().
Algoritmo:
null
.strspn()
para esto), llámalo start
.strpbrk()
para esto), llámalo end
.start
para end
en ese recuerdo.Ventaja:
strtok()
y strsep()
hace.Implementación:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
/*
* alloc_str function allocates memory and copy substring
* to allocated memory.
*/
static char * alloc_str (const char * start, const char * end) {
if (!start || !end || (start >= end)) {
return NULL;
}
char * tmp = malloc (end - start + 1);
if (tmp) {
memcpy (tmp, start, end - start);
tmp[end - start] = '\0';
} else {
fprintf (stderr, "Failed to allocate memory\n");
exit (EXIT_FAILURE);
}
return tmp;
}
/*
* str_split function returns the next token which is sequences of contiguous
* characters separated by any of the characters that are part of delimiters.
*
* Parameters:
* p_str : Address of pointer to the string that you want to split.
* sep : A set of characters that delimit the pieces in the string.
*
* Behaviour is undefined if sep is not a pointer to a null-terminated string.
*
* Return :
* Returns the pointer to dynamically allocated memory where the token is copied.
* If p_str is NULL or empty string, NULL is returned.
*/
char * str_split (char ** p_str, const char * sep) {
char * token = NULL;
if (*p_str && **p_str) {
char * p_end;
// skip separator
*p_str += strspn(*p_str, sep);
p_end = *p_str;
// find separator
p_end = strpbrk (p_end, sep);
// strpbrk() returns null pointer if no such character
// exists in the input string which is part of sep argument.
if (!p_end) {
p_end = *p_str + strlen (*p_str);
}
token = alloc_str (*p_str, p_end);
*p_str = p_end;
}
return token;
}
/*==================================================*/
/*==================================================*/
/*
* Just a helper function
*/
void token_helper (char * in_str, const char * delim) {
printf ("\nInput string : ");
if (in_str) printf ("\"%s\"\n", in_str);
else printf ("NULL\n");
if (delim) printf ("Delimiter : \"%s\"\n", delim);
char * ptr = in_str;
char * token = NULL;
printf ("Tokens:\n");
while ((token = str_split(&ptr, delim)) != NULL) {
printf ("-> %s\n", token);
/* You can assign this token to a pointer of an array of pointers
* and return that array of pointers from this function.
* Since, this is for demonstration purpose, I am
* freeing the allocated memory now.
*/
free (token);
}
}
/*
* Driver function
*/
int main (void) {
/* test cases */
char string[100] = "hello world!";
const char * delim = " ";
token_helper (string, delim);
strcpy (string, " hello world,friend of mine!");
delim = " ,";
token_helper (string, delim);
strcpy (string, "Another string");
delim = "-!";
token_helper (string, delim);
strcpy (string, " one more -- string !");
delim = "- !";
token_helper (string, delim);
strcpy (string, "");
delim = " ";
token_helper (string, delim);
token_helper (NULL, "");
strcpy (string, "hi");
delim = " -$";
token_helper (string, delim);
strcpy (string, "Give papa a cup of proper coffee in a copper coffee cup.");
delim = "cp";
token_helper (string, delim);
strcpy (string, "JAN,FEB,MAR,APR,MAY,JUN,JUL,AUG,SEP,OCT,NOV,DEC");
delim = ",";
token_helper (string, delim);
return 0;
}
Producción:
# ./a.out
Input string : "hello world!"
Delimiter : " "
Tokens:
-> hello
-> world!
Input string : " hello world,friend of mine!"
Delimiter : " ,"
Tokens:
-> hello
-> world
-> friend
-> of
-> mine!
Input string : "Another string"
Delimiter : "-!"
Tokens:
-> Another string
Input string : " one more -- string !"
Delimiter : "- !"
Tokens:
-> one
-> more
-> string
Input string : ""
Delimiter : " "
Tokens:
Input string : NULL
Delimiter : ""
Tokens:
Input string : "hi"
Delimiter : " -$"
Tokens:
-> hi
Input string : "Give papa a cup of proper coffee in a copper coffee cup."
Delimiter : "cp"
Tokens:
-> Give
-> a
-> a a
-> u
-> of
-> ro
-> er
-> offee in a
-> o
-> er
-> offee
-> u
-> .
Input string : "JAN,FEB,MAR,APR,MAY,JUN,JUL,AUG,SEP,OCT,NOV,DEC"
Delimiter : ","
Tokens:
-> JAN
-> FEB
-> MAR
-> APR
-> MAY
-> JUN
-> JUL
-> AUG
-> SEP
-> OCT
-> NOV
-> DEC
Ya sé que llegó tarde a la fiesta, pero aquí hay 2 funciones más para jugar y probablemente ajustarse aún más a sus necesidades (código fuente en la parte inferior del puesto)
Véase también el Notas de implementaciónmás abajo, para decidir qué función se adapta mejor a sus necesidades.
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <stdbool.h> // C99
// tokenize destructively
char **str_toksarray_alloc(
char **strp, /* InOut: pointer to the source non-constant c-string */
const char *delim, /* c-string containing the delimiting chars */
size_t *ntoks, /* InOut: # of tokens to parse/parsed (NULL or *ntoks==0 for all tokens) */
bool keepnulls /* false ignores empty tokens, true includes them */
);
// tokenize non-destructively
char **str_toksarray_alloc2(
const char *str, /* the source c-string */
const char *delim,
size_t *ntoks,
bool keepnulls
);
Sus prototipos son casi idénticos, excepto por la cadena de origen (strp
y str
respectivamente).
strp
(puntero a cadena) es la dirección de una cadena C no constante ya asignada, que se tokenizará en el lugar. str
es una cadena c que no está alterada (incluso puede ser una cadena literal). Por cuerda C me refiero a un nul
-buffer terminado de caracteres. El resto de los argumentos son los mismos para ambas funciones.
Para analizar todos los tokens disponibles, silencio ntoks
(es decir, configúrelo en 0 antes de pasarlo a cualquiera de las funciones o páselo como un NULL
puntero). De lo contrario, las funciones analizan hasta *ntoks
fichas, o hasta que no haya más fichas (lo que suceda primero). En cualquier caso, cuando ntoks
es non-NULL
se actualiza con el recuento de tokens analizados con éxito.
Nótese también que un no silenciado ntoks
determina cuántos punteros se asignarán. Por lo tanto, si la cadena de origen contiene, digamos, 10 tokens y configuramos ntoks
a 1000, terminaremos con 990 punteros asignados innecesariamente. Por otro lado, si la cadena de origen contiene, digamos, 1000 tokens pero solo necesitamos los primeros 10, configurando ntoks
a 10 suena como una opción mucho más sabia.
Ambas funciones asignar y devolver una matriz de char-pointerspero str_toksarray_alloc()
hace que apunten a los tokens en la propia cadena de origen modificada, mientras que str_toksarray_alloc2()
los hace apuntar a copias asignadas dinámicamente de los tokens (ese 2 al final de su nombre indica los 2 niveles de asignación).
La matriz devuelta se adjunta con un NULL
puntero centinela, que no se tiene en cuenta en el valor devuelto de ntoks
(dicho de otro modo, cuando non-NULL
, ntoks
devuelve a la persona que llama la longitud de la matriz devuelta, no su tamaño de primer nivel).
Cuando keepnulls
se establece en true
, las fichas resultantes son similares a lo que esperaríamos de la strsep() función. Principalmente significa que los delimitadores consecutivos en la cadena de origen producen tokens vacíos (nulos), y si delim
es una cadena c vacía o ninguno de sus caracteres delimitadores contenidos se encontró en la cadena de origen, el resultado es solo 1 token: la cadena de origen. Contrariamente a strsep()los tokens vacíos se pueden ignorar configurando keepnulls
para false
.
Ha fallado Las llamadas de las funciones se pueden identificar comparando su valor de retorno con NULL
o comprobando el valor devuelto de ntoks
contra 0 (siempre que ntoks
era non-NULL
). Sugiero verificar siempre contra fallas antes de intentar acceder a la matriz devuelta, porque las funciones incluyen verificaciones de cordura que pueden posponer fallas inmediatas (por ejemplo, pasar un NULL
puntero como cadena de origen).
Sobre el éxito, la persona que llama debe liberar la matriz cuando haya terminado. Para str_toksarray_alloc()
un simple gratis() es suficiente. Para str_toksarray_alloc2()
se trata de un bucle, debido al segundo nivel de asignación. Él NULL
centinela (o el valor devuelto de un non-NULL
ntoks
) hace que esto sea trivial, pero también estoy proporcionando una toksarray_free2()
función a continuación, para todas las abejas perezosas por ahí 🙂
A continuación se muestran ejemplos simplificados que utilizan ambas funciones.
Deberes:
const char *src = ";b,test,Tèst,;;cd;ελληνικά,nørmälize,;string to";
const char *delim = ";,";
bool keepnulls = true;
size_t ntoks = 0;
str_toksarray_alloc():
// destructive (use copy of src)
char *scopy = strdup( src );
if (!scopy) { ... }; // handle strdup failure
printf( "%s\n", src );
char **arrtoks = str_toksarray_alloc( &scopy, delim, &ntoks, keepnulls );
printf( "%lu tokens read\n", ntoks );
if ( arrtoks ) {
for (int i=0; arrtoks[i]; i++) {
printf( "%d: %s\n", i, arrtoks[i] );
}
}
free( scopy );
free( arrtoks );
/* OUTPUT
;b,test,Tèst,;;cd;ελληνικά,nørmälize,;string to
11 tokens read
0:
1: b
2: test
3: Tèst
4:
5:
6: cd
7: ελληνικά
8: nørmälize
9:
10: string to
*/
str_toksarray_alloc2():
// non-destructive
keepnulls = false; // reject empty tokens
printf( "%s\n", src );
arrtoks = str_toksarray_alloc2( src, delim, &ntoks, keepnulls );
printf( "%lu tokens read\n", ntoks );
if ( arrtoks ) {
for (int i=0; arrtoks[i]; i++) {
printf( "%d: %s\n", i, arrtoks[i] );
}
}
toksarray_free2( arrtoks ); // dangling arrtoks
// or: arrtoks = toksarray_free2( arrtoks ); // non-dangling artoks
/* OUTPUT
;b,test,Tèst,;;cd;ελληνικά,nørmälize,;string to
7 tokens read
0: b
1: test
2: Tèst
3: cd
4: ελληνικά
5: nørmälize
6: string to
*/
Ambas funciones utilizan strsep() por la tokenización que los hace a salvo de amenazas, pero no es una función estándar. Si no se proporciona, siempre puede usar una implementación de código abierto (como GNU o de manzana por ejemplo). Lo mismo ocurre con la función strdup() que se usa en str_toksarray_alloc2()
(su implementación es trivial, pero de nuevo aquí está GNU y de manzana por ejemplo).
Un efecto secundario del uso strsep() en str_toksarray_alloc()
es que el puntero de inicio de la cadena de origen sigue moviéndose al siguiente token en cada paso del ciclo de análisis. Esto significa que la persona que llama no podrá liberar la cadena analizada, a menos que haya guardado la dirección de inicio en un puntero adicional. Les ahorramos la molestiahaciéndolo localmente en la función, usando el strpSaved
puntero. str_toksarray_alloc2()
no se ve afectado por esto, porque no toca la cadena de origen.
Una diferencia principal entre las 2 funciones es que str_toksarray_alloc()
no asigna memoria para los tokens encontrados. Más bien asigna espacio solo para los punteros de matriz y los establece apuntando directamente a la cadena de origen. Esto funciona porque strsep() nul
-termina los tokens encontrados en el lugar. Esta dependencia puede complicar su código de soporte, pero con cadenas grandes también puede marcar una gran diferencia en el rendimiento. Si conservar la cadena de origen no es importante, también puede marcar una gran diferencia en el consumo de memoria.
Por otro lado, str_toksarray_alloc2()
asigna y devuelve una matriz autosuficiente de copias de los tokens asignadas dinámicamente, sin más dependencias. Lo hace, en primer lugar, creando la matriz a partir de un duplicado local de la cadena de origen y, en segundo lugar, duplicando el contenido de los tokens reales en la matriz. Esto es mucho más lento y deja una huella de memoria mucho mayor en comparación con str_toksarray_alloc()
, pero no tiene más dependencias y no establece requisitos especiales para la naturaleza de la cadena de origen. Esto hace que sea más fácil escribir código de soporte más simple (por lo tanto, mejor mantenible).
Otra diferencia entre las 2 funciones es el primer nivel de asignación (los punteros de matriz) cuando ntoks
es apagado. Ambos analizan todos los tokens disponibles, pero adoptan enfoques bastante diferentes. str_toksarray_alloc()
utiliza alloc-ahead con un tamaño inicial de 16 (char-pointers), duplicándolo a pedido en el ciclo de análisis. str_toksarray_alloc2()
hace un primer pase contando todos los tokens disponibles, luego asigna esa cantidad de punteros de caracteres solo una vez. Ese primer pase se realiza con una función de ayuda. str_toksfound()
que utiliza las funciones estándar strpbrk() y strchr(). También proporciono el código fuente de esa función, más abajo.
Depende de usted decidir qué enfoque es mejor, según las necesidades de su proyecto. Siéntase libre de ajustar el código de cada función para cualquier enfoque y tomarlo desde allí.
Diría que, en promedio y para cadenas realmente grandes, alloc-ahead es mucho más rápido, especialmente cuando el tamaño inicial y el factor de crecimiento se ajustan con precisión caso por caso (haciéndolos funcionar como parámetros, por ejemplo). Guardando ese pase extra con todos esos strchr()
‘arena strpbrk()
‘s puede hacer una diferencia allí. Sin embargo, con cadenas relativamente pequeñas, que es prácticamente la norma, asignar por adelantado solo un montón de punteros de caracteres es simplemente una exageración. No duele, pero desordena el código sin una buena razón en este caso. De todos modos, siéntete libre de elegir el que más te convenga.
Lo mismo ocurre con estas 2 funciones. diría que en la mayoría de los casos str_toksarray_alloc2()
es mucho más fácil de manejar, ya que la memoria y el rendimiento rara vez son un problema con cadenas pequeñas o medianas. Si tiene que lidiar con cadenas enormes, considere usar str_toksarray_alloc()
(aunque en esos casos, debe implementar una función de análisis de cadenas especializada, cercana a las necesidades de su proyecto y las especificaciones de su entrada).
Vaya, creo que eso fue un poco más que solo 2 centavos (lol).
De todos modos, aquí está el código de las 2 funciones y las auxiliares (he eliminado la mayoría de sus comentarios de descripción, ya que ya he cubierto casi todo).
str_toksarray_alloc():
// ----------------------------------------
// Tokenize destructively a nul-terminated source-string.
// Return a dynamically allocated, NULL terminated array of char-pointers
// each pointing to each token found in the source-string, or NULL on error.
//
char **str_toksarray_alloc(char **strp, const char *delim, size_t *ntoks, bool keepnulls)
{
// sanity checks
if ( !strp || !*strp || !**strp || !delim ) {
goto failed;
}
char *strpSaved = *strp; // save initial *strp pointer
bool ntoksOk = (ntoks && *ntoks); // false when ntoks is muted
size_t _ntoks = (ntoksOk ? *ntoks : 16); // # of tokens to alloc-ahead
// alloc array of char-pointers (+1 for NULL sentinel)
char **toksarr = malloc( (_ntoks+1) * sizeof(*toksarr) );
if ( !toksarr ) {
goto failed;
}
// Parse *strp tokens into the array
size_t i = 0; // # of actually parsed tokens
char *tok;
while ( (tok = strsep(strp, delim)) ) {
// if requested, ignore empty tokens
if ( *tok == '\0' && !keepnulls ) {
continue;
}
// non-muted ntoks reached? we are done
if ( ntoksOk && i == _ntoks ) {
*ntoks = i;
break;
}
// muted ntoks & ran out of space? double toksarr and keep parsing
if ( !ntoksOk && i == _ntoks ) {
_ntoks *= 2;
char **tmparr = realloc( toksarr, (_ntoks+1) * sizeof(*tmparr) );
if ( !tmparr ) {
*strp = strpSaved;
free( toksarr );
goto failed;
}
toksarr = tmparr;
}
toksarr[i++] = tok; // get token address
}
toksarr[i] = NULL; // NULL sentinel
*strp = strpSaved; // restore initial *strp pointer
if (ntoks) *ntoks = i; // pass to caller # of parsed tokens
return toksarr;
failed:
if (ntoks) *ntoks = 0;
return NULL;
}
str_toksarray_alloc2():
// ----------------------------------------
// Tokenize non-destructively a nul-terminated source-string.
// Return a dynamically allocated, NULL terminated array of dynamically
// allocated and nul-terminated string copies of each token found in the
// source-string. Return NULL on error.
// The 2 at the end of the name means 2-levels of allocation.
//
char **str_toksarray_alloc2( const char *str, const char *delim, size_t *ntoks, bool keepnulls )
{
// sanity checks
if ( !str || !*str || !delim ) {
if (ntoks) *ntoks = 0;
return NULL;
}
// make a copy of str to work with
char *_str = strdup( str );
if ( !_str ) {
if (ntoks) *ntoks = 0;
return NULL;
}
// if ntoks is muted we'll allocate str_tokscount() tokens, else *ntoks
size_t _ntoks = (ntoks && *ntoks) ? *ntoks : str_tokscount(_str, delim, keepnulls);
if ( _ntoks == 0 ) { // str_tokscount() failed
goto fail_free_str;
}
// alloc the array of strings (+1 for an extra NULL sentinel)
char **toksarr = malloc( (_ntoks+1) * sizeof(*toksarr) );
if ( !toksarr ) {
goto fail_free_str;
}
// Parse str tokens and duplicate them into the array
size_t i = 0; // # of actually parsed tokens
char *tok;
while ( i < _ntoks && (tok = strsep(&_str, delim)) ) {
// if requested, skip empty tokens
if ( *tok == '\0' && !keepnulls ) {
continue;
}
// duplicate current token into the array
char *tmptok = strdup( tok );
if ( !tmptok ) {
goto fail_free_arr;
}
toksarr[i++] = tmptok;
}
toksarr[i] = NULL; // NULL sentinel
free( _str ); // release the local copy of the source-string
if (ntoks) *ntoks = i; // pass to caller the # of parsed tokens
return toksarr;
// cleanup before failing
fail_free_arr:
for (size_t idx=0; idx < i; idx++) {
free( toksarr[idx] );
}
free( toksarr );
fail_free_str:
free( _str );
if (ntoks) *ntoks = 0;
return NULL;
}
str_tokscount() – función auxiliar, utilizada por str_toksarr_alloc2():
// ----------------------------------------
// Return the count of tokens present in a nul-terminated source-string (str),
// based on the delimiting chars contained in a 2nd nul-terminated string (delim).
// If the boolean argument is false, empty tokens are excluded.
//
// To stay consistent with the behavior of strsep(), the function returns 1 if
// delim is an empty string or none of its delimiters is found in str (in those
// cases the source-string is considered a single token).
// 0 is returned when str or delim are passed as NULL pointers, or when str is
// passed as an empty string.
//
size_t str_tokscount( const char *str, const char *delim, bool keepnulls )
{
// sanity checks
if ( !str || !*str || !delim ) {
return 0;
}
const char *tok = str;
size_t nnulls = strchr(delim, *str) ? 1 : 0;
size_t ntoks = 1; // even when no delims in str, str counts as 1 token
for (; (str = strpbrk(tok, delim)); ntoks++ ) {
tok = ++str;
if ( strchr(delim, *str) ) {
nnulls++;
}
}
return keepnulls ? ntoks : (ntoks - nnulls);
}
toksarray_free2() – Úselo en la matriz devuelta por str_toksarr_alloc2():
// ----------------------------------------
// Free a dynamically allocated, NULL terminated, array of char-pointers
// with each such pointer pointing to its own dynamically allocated data.
// Return NULL, so the caller has the choice of assigning it back to the
// dangling pointer. The 2 at the end of the name means 2-levels of deallocation.
//
// NULL terminated array means ending with a NULL sentinel.
// e.g.: toksarr[0] = tok1, ..., toksarr[len] = NULL
//
char **toksarray_free2( char **toksarr )
{
if ( toksarr ) {
char **toks = toksarr;
while ( *toks ) { // walk until NULL sentinel
free( *toks++ );
}
free( toksarr );
}
return NULL;
}
Puedes usar el
strtok
función de la biblioteca estándar para lograr lo mismo.–Daniel Kamil Kozar
9 de febrero de 2012 a las 12:08
stackoverflow.com/questions/8461170/…
– PIXY AZUL
9 de febrero de 2012 a las 12:56
Un comentario… el punto clave para un
strtok()
la funcion de la familia es la comprensionstatic variables
en C. es decir, cómo se comportan entre las sucesivas llamadas de funciones en las que se utilizan. Ver mi código a continuación– fnisi
21 de febrero de 2016 a las 19:48
strtok
es no una solución para este problema por varias razones: modifica la cadena de origen, tiene un estado estático oculto que hace que no vuelva a entrar, manejará secuencias de delimitadores como un solo delimitador, lo que parece incorrecto para,
y como consecuencia no dividirá las cadenas vacías al principio, en medio ni al final de,X,,Y,
. no usarstrtok
.– chqrlie
28 de diciembre de 2021 a las 11:26