C strtok () splits the string into tokens, but keeps old data intact

I have the following code:

#include <stdio.h> #include <string.h> 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; } 

Execution Output:

 $ ./str Firstname: John Lastname: Doe City: Melbourne Zip: 6270 Country: AU STR: John OLDSTR: John 

Why can't I store old data or str or oldstr , what am I doing wrong, and how can I not change data or store it?

+1
source share
4 answers

when you execute strtok(NULL, "|") strtock find token and put the zero in place (replace the token with \0 ) and change the line.

you str , becomes:

 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) 

Consider the diagram because char '0' and 0 are unstable (line 6270 char in the figure in brackets indicates ' , where for \0 0 is a number)

when you print str using %s , it prints characters up to the first \0 , which John

So that your original line does not change, you must copy str to some tempstr variable, and then use this tempstr line in strtok() :

 char str[] = "John|Doe|Melbourne|6270|AU"; char* tempstr = calloc(strlen(str)+1, sizeof(char)); strcpy(tempstr, str); 

Now use this line tempstr instead of str in your code.

+14
source

strtok requires a writable input line, and it modifies the input line. If you want to save the input line, you must first make a copy of it.

For instance:

 char str[] = "John|Doe|Melbourne|6270|AU"; char oldstr[32]; strcpy(oldstr, str); // Use strncpy if you don't know // the size of str 
+1
source

Since oldstr is just a pointer, assignment will not create a new copy of your string.

Copy it before passing str to strtok :

  char *oldstr=malloc(sizeof(str)); strcpy(oldstr,str); 

Your patched version:

 #include <stdio.h> #include <string.h> #include<malloc.h> 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; } 

EDIT:

As mentioned in @CodeClown, in your case it is better to use strncpy . And instead of manually fixing the sizes of fname , etc., you can have pointers in place and allocate memory, as required, no more and no less. This way you can avoid writing to the buffer outside the bounds.

Another idea: it would assign the result of strtok the *fname , *lname , etc. instead of arrays. It seems that strtok intended to be used this way after looking at the accepted answer.

Caution: this way, if you change str further, that will be reflected in fname , lname . Because they simply point to str data, but not to new blocks of memory. So use oldstr for other manipulations.

 #include <stdio.h> #include <string.h> #include<malloc.h> 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; } 
+1
source

You simply copy the pointer to the string, but not the string itself. Use strncpy() to create a copy.

 char *oldstr = str; // just copy of the address not the string itself! 
0
source

All Articles