Nested strtok function problem in C
You cannot do that with strtok()
; use strtok_r()
from POSIX or strtok_s()
from Microsoft if they are available, or rethink your design.
char *strtok_r(char *restrict s, const char *restrict sep,
char **restrict lasts);
char *strtok_s(char *strToken, const char *strDelimit, char **context);
These two functions are interchangeable.
Note that a variant strtok_s()
is specified in an optional part of C11 (Annex K in ISO/IEC 9899:2011). However, few suppliers other than Microsoft have implemented the interfaces in that section of the standard. The version of strtok_s()
specified in Annex K has a different interface from Microsoft's strtok_s()
— similar problems bedevil a number of the other functions specified in Annex K.
With strtok_r()
#include <string.h>
#include <stdio.h>
int main(void)
{
char str[] = "a;b;c;d;e\nf;g;h;i;j\n1;2;3;4;5\n";
char *end_str;
char *token = strtok_r(str, "\n", &end_str);
while (token != NULL)
{
char *end_token;
printf("a = %s\n", token);
char *token2 = strtok_r(token, ";", &end_token);
while (token2 != NULL)
{
printf("b = %s\n", token2);
token2 = strtok_r(NULL, ";", &end_token);
}
token = strtok_r(NULL, "\n", &end_str);
}
return 0;
}
Results
a = a;b;c;d;e
b = a
b = b
b = c
b = d
b = e
a = f;g;h;i;j
b = f
b = g
b = h
b = i
b = j
a = 1;2;3;4;5
b = 1
b = 2
b = 3
b = 4
b = 5
Without strtok_r()
This works in context - provided that the data ends with a newline.
#include <string.h>
#include <stdio.h>
int main(void)
{
char data[] = "a;b;c;d;e\nf;g;h;i;j\n1;2;3;4;5\n";
char *string = data;
char *token = strchr(string, '\n');
while (token != NULL)
{
/* String to scan is in string..token */
*token++ = '\0';
printf("a = %s\n", string);
char *token2 = strtok(string, ";");
while (token2 != NULL)
{
printf("b = %s\n", token2);
token2 = strtok(NULL, ";");
}
string = token;
token = strchr(string, '\n');
}
return 0;
}
Output
a = a;b;c;d;e
b = a
b = b
b = c
b = d
b = e
a = f;g;h;i;j
b = f
b = g
b = h
b = i
b = j
a = 1;2;3;4;5
b = 1
b = 2
b = 3
b = 4
b = 5
strtok_r
is the best and safest solution, but there is also a way to do it with strtok
:
#include <string.h>
#include <stdio.h>
int main ()
{
char str[] = "a;b;c;d;e\nf;g;h;i;j\n1;2;3;4;5\n";
char *line;
char *token;
char buf[256];
for (line = strtok (str, "\n"); line != NULL;
line = strtok (line + strlen (line) + 1, "\n"))
{
strncpy (buf, line, sizeof (buf));
printf ("Line: %s\n", buf);
for (token = strtok (buf, ";"); token != NULL;
token = strtok (token + strlen (token) + 1, ";"))
{
printf ("\tToken: %s\n", token);
}
}
return 0;
}
Output:
Line: a;b;c;d;e
Token: a
Token: b
Token: c
Token: d
Token: e
Line: f;g;h;i;j
Token: f
Token: g
Token: h
Token: i
Token: j
Line: 1;2;3;4;5
Token: 1
Token: 2
Token: 3
Token: 4
Token: 5