Tengo el siguiente código:
#include #include int main (void) { char str[] = "John|Doe|Melbourne|6270|AU"; char fname[32], lname[32], city[32], zip[32], country[32]; char *oldstr = str; strcpy(fname, strtok(str, "|")); strcpy(lname, strtok(NULL, "|")); strcpy(city, strtok(NULL, "|")); strcpy(zip, strtok(NULL, "|")); strcpy(country, strtok(NULL, "|")); printf("Firstname: %s\n", fname); printf("Lastname: %s\n", lname); printf("City: %s\n", city); printf("Zip: %s\n", zip); printf("Country: %s\n", country); printf("STR: %s\n", str); printf("OLDSTR: %s\n", oldstr); return 0; }
Salida de ejecución:
$ ./str Firstname: John Lastname: Doe City: Melbourne Zip: 6270 Country: AU STR: John OLDSTR: John
¿Por qué no puedo mantener los datos antiguos ni en la str
ni en el oldstr
¿Qué estoy haciendo mal y cómo no puedo alterar los datos o guardarlos?
cuando haces strtok(NULL, "|")
strtock encuentra el token y coloca nulo en su lugar ( reemplaza el token con \0
) y modifica la cadena.
tu str
, se convierte en
char str[] = John0Doe0Melbourne062700AU; Str array in memory +------------------------------------------------------------------------------------------------+ |'J'|'o'|'h'|'n'|0|'D'|'o'|'e'|0|'M'|'e'|'l'|'b'|'o'|'u'|'r'|'n'|'e'|0|'6'|'2'|'7'|'0'|0|'A'|'U'|0| +------------------------------------------------------------------------------------------------+ ^ replace | with \0 (ASCII value is 0)
Considerar que el diagtwig es importante porque el carácter '0'
y 0
son difidentes (en la cadena 6270 están caracterizados por caracteres con paréntesis entre '
donde para \0
0 es el número)
cuando imprime str usando %s
, imprime caracteres hasta la primera \0
que es John
Para mantener su str original sin cambios, debe pujar copy str en alguna variable tempstr y luego usar esa cadena tempstr
en strtok()
:
char str[] = "John|Doe|Melbourne|6270|AU"; char* tempstr = calloc(strlen(str)+1, sizeof(char)); strcpy(tempstr, str);
Ahora use esta cadena tempstr
en lugar de str en su código.
Debido a que oldstr
es solo un puntero, una asignación no hará una nueva copia de su cadena.
Cópialo antes de pasar str al strtok
:
char *oldstr=malloc(sizeof(str)); strcpy(oldstr,str);
Su versión corregida:
#include #include #include int main (void) { char str[] = "John|Doe|Melbourne|6270|AU"; char fname[32], lname[32], city[32], zip[32], country[32]; char *oldstr = malloc(sizeof(str)); strcpy(oldstr,str); ................... free(oldstr); return 0; }
EDITAR:
Como mencionó @CodeClown, en su caso, es mejor usar strncpy
. Y en lugar de fijar de fname
los tamaños de fname
etc., puede tener punteros en su lugar y asignar la memoria según sea necesario, ni más ni menos. De esa manera puedes evitar escribir en el búfer fuera de límites …
Otra idea: sería asignar el resultado de strtok
a los punteros *fname
, *lname
, etc. en lugar de matrices. Parece que el strtok
está diseñado para ser utilizado de esa manera después de ver la respuesta aceptada.
Precaución: de esta manera, si cambia la str
adicional, eso se reflejaría en fname
, lname
también. Porque, solo apuntan a datos de str
pero no a nuevos bloques de memoria. Entonces, usa oldstr
para otras manipulaciones.
#include #include #include int main (void) { char str[] = "John|Doe|Melbourne|6270|AU"; char *fname, *lname, *city, *zip, *country; char *oldstr = malloc(sizeof(str)); strcpy(oldstr,str); fname=strtok(str,"|"); lname=strtok(NULL,"|"); city=strtok(NULL, "|"); zip=strtok(NULL, "|"); country=strtok(NULL, "|"); printf("Firstname: %s\n", fname); printf("Lastname: %s\n", lname); printf("City: %s\n", city); printf("Zip: %s\n", zip); printf("Country: %s\n", country); printf("STR: %s\n", str); printf("OLDSTR: %s\n", oldstr); free(oldstr); return 0; }
strtok
requiere una cadena de entrada grabable y modifica la cadena de entrada. Si desea mantener la cadena de entrada, primero debe hacer una copia de ella.
Por ejemplo:
char str[] = "John|Doe|Melbourne|6270|AU"; char oldstr[32]; strcpy(oldstr, str); // Use strncpy if you don't know // the size of str
Simplemente copie el puntero a la cadena, pero no la cadena en sí. Use strncpy()
para crear una copia.
char *oldstr = str; // just copy of the address not the string itself!