Reputation: 31
I have this string: "Alaska:(3,4)"
and I want "Alaska"
, "3"
, "4"
sub-strings. But I have a problem.
cityName = strtok(str , ":");
printf("name : %s\n",cityName);
temp = strtok(NULL , "(");
printf("%s\n",temp);
temp = strtok(NULL , ",");
printf("%s\n",temp);
temp = strtok(NULL, ")");
printf("%s\n",temp);
For this code I get this output:
name : Alaska
3,4)
(null)
(null)
What's wrong?
Upvotes: 2
Views: 110
Reputation: 42588
strtok(3)
doesn't like empty separators. Do you have access to strsep(3)
.
char str[] = "Alaska:(3,4)";
char *p = str;
char *temp;
char *cityName = strsep(&p , ":");
printf("name : %s\n",cityName);
temp = strsep(&p , "(");
printf("%s\n",temp);
temp = strsep(&p , ",");
printf("%s\n",temp);
temp = strsep(&p, ")");
printf("%s\n",temp);
Upvotes: 0
Reputation: 45654
Please take a look at the documentation for strtok
:
A sequence of calls to the strtok function breaks the string pointed to by s1 into a sequence of tokens, each of which is delimited by a character from the string pointed to by s2. The first call in the sequence has a non-null first argument; subsequent calls in the sequence have a null first argument. The separator string pointed to by s2 may be different from call to call.
The first call in the sequence searches the string pointed to by s1 for the first character that is not contained in the current separator string pointed to by s2. If no such character is found, then there are no tokens in the string pointed to by s1 and the strtok function returns a null pointer. If such a character is found, it is the start of the first token.
The strtok function then searches from there for a character that is contained in the current separator string. If no such character is found, the current token extends to the end of the string pointed to by s1, and subsequent searches for a token will return a null pointer. If such a character is found, it is overwritten by a null character, which terminates the current token. The strtok function saves a pointer to the following character, from which the next search for a token will start.
In short, strtok
searches for the first character not in delimiters for the start of the sequence, and then for the first character in delimiters for the end of the sequence.
That means your last two calls to strtok
return NULL
, so the printf
-calls are Undefined Behavior, anything may happen.
Better use sscanf
or roll your own parser (likely does not need any longer).
If you want to stay with strtok
, correct your delimiters and only try to get three tokens:
cityName = strtok(str , ":");
printf("name : %s\n",cityName);
temp = strtok(NULL , "(,)");
printf("%s\n",temp);
temp = strtok(NULL , "(,)");
printf("%s\n",temp);
Still, consider at least moving to strtok_s
to avoid data-races and make your code reentrant.
Upvotes: 0
Reputation: 22542
The reason why your implementation does not work is because strtok
has recognised the string as fully parsed after the second call (because nothing was found before the first token). You need to restart the parsing after the second call.
void bar(char * str) {
char * cityName, *temp;
cityName = strtok(str , ":");
printf("name : %s\n",cityName);
temp = strtok(NULL , "(");
printf("%s\n",temp);
temp = strtok(temp , ","); // restart parsing here
printf("%s\n",temp);
temp = strtok(NULL, ")");
printf("%s\n",temp);
}
Please note that strtok
is destructive on the input string and is not thread-safe.
Have you considered to use sscanf
family? It's a bit easier to use if you have a fixed format.
void foo(char * str) {
char city[32], num[2][32];
sscanf(str, "%[^:]:(%[^,],%[^)])", city, num[0], num[1]);
printf("%s\n%s\n%s\n", city, num[0], num[1]);
}
Upvotes: 1