was stuck on strtok() why it modifies the original string... But then someone told strtok_r() won't do that... While I test it out I find no change. strtok_r() also modifies the original string. At the end of the call to strtok_r() original string has changed.
This is not true. strtok_r(3)
does change the original string, as strtok(3)
did previously, what it does differently is to accept a pointer to char *
from you, to store the information (the point it was when it found the last string) it needs to use between calls, so it can be reentered from different threads making the function reentrant.
Strtok is an archaic function, that predates from the times of early C. It modifies the original string to avoid using dynamically allocated memory, which is faster, but if you want to preserve the original string you can always call strdup(3)
on the original string, operate on the obtained copy, and then return the memory used with free(3)
when you are finished.
Anyway, even if you use strtok(2)
in a locally memory allocated buffer, it continues to be non-reentrant, as it uses global static data to remember the position on the string it is parsing, so it can continue where it stopped to get the next substring. If you want to use strtok(3)
nested in another loop, or you want it to be reentered recursively in a recursive procedure, then you have to switch to the _r
suffixed one, or you'll lost the pointer in the outer call with the calls to the inner loop strtok()
. For example:
char buffer[] = "root:0:0:x:System Administrator,Administrators Dept.,5742,+300 40 86 26:/root:/bin/sh";
/* look for password fields */
for(p = strtok(string, ":"); p; p = strtok(NULL, ":")) {
/* separate items with commas */
for (q = strtok(p, ","); q; q = strtok(NULL, ",")) {
.... /* the last call to strtok(NULL, ",") broke the point where
* the first call to strtok(NULL, ":") was looking at, in the
* outer loop. */
you need to change to:
char *p1;
for(p = strtok_r(string, ":", &p1); p; p = strtok_r(NULL, ":", &p1)) {
char *p2;
for (q = strtok_r(p, ",", &p2); q; q = strtok_r(NULL, ",", &p2)) {
.... /* nothing breaks, if p1 and p2 are different variables. */
an example of using strdup()
could be:
char *p1, *working_string = strdup(original_string);
for(p = strtok_r(workin_string, ":", &p1); p; p = strtok_r(NULL, ":", &p1)) {
char *p2;
for (q = strtok_r(p, ",", &p2); q; q = strtok_r(NULL, ",", &p2)) {
.... /* nothing breaks, if p1 and p2 are different variables. */
}
}
...
free(working_string); /* or whenever you feel it can be freed */