strtok函数及注意事项
- 函数原型及其基本应用
strtok函数是用来分解字符串的,其原型是:
char *strtok(char str[], const char *delim);
其中str是要分解的字符串,delim是字符串中用来分解的字符,该函数返回分解后的字符串的起始位置指针。之所以是分解,就是说并没有生成新的字符串,只是在源字符串上面做了一些手脚,使得源字符串发生了变化,所以一定要注意,源字符串发生了变化!!!
先从最简单的应用来看,看下面的例1。
// 例1
#include <string.h>
void main()
{
char s[] = "192.168.0.26";
char *delim = ".";
char *p;
printf("%s ", strtok(s, delim));
while((p = strtok(NULL, delim)))
printf("%s ", p);
printf("\n");
}
从例1中就可以看出strtok函数的基本使用方法,输入一个字符串数组,然后就可以将其按照一定的分隔符(例1中为".")将一个长的字符串分割成一个个短的字符串。这里需要注意的是,在对一个长字符串分割的时候,第一次调用时,strtok函数的第一个参数传入要分割的字符串,而第二次以及后面再次调用该函数的时候,strtok函数的第一个参数应该传入NULL,这是因为在strtok第一个参数为NULL的时候,该函数默认使用上一次未分割完的字符串的未分割的起始位置作为本次分割的起始位置,直到分割结束为止。
这个例子就最常见的基本应用,但是仅仅知道这些很容易忽略很多细节问题,后面本文将继续讨论一些值得注意的问题。
- 使用注意事项1
这里首先需要强调的是strtok函数在进行字符串分解的时候,其第一个参数,即char str[]是在变化的,就像前面说过的一样,其只是对源字符串动了一些手脚,也就是改变了源字符串。以例1中的字符串来说,"192.168.0.26"是源字符串,在调用strtok对其分解结束后,字符串变成了"19201680026",注意其中红色加粗部分是把'.'替换成了'\0',也就是替换成了字符串结束标志字符,这样在打印或使用的时候都会使得前面的字符串成为一个看起来独立的字符串,即"192"、"168"、"0"、"26",这些字符串还是在源字符串中,只是后面都有了自己的字符串结束标志'\0'而已。
- 使用注意事项2
在注意事项1中提到了源字符串发生了变化,同时注意到strtok函数原型的第一个参数是一个字符数组char str[],虽然说传递参数时实参可以是一个指针,但是这个指针如果是字符串常量指针,那么就会引起程序运行时崩溃,因为源字符串要发生变化,而字符串常量是不能被改变的,例如下面的例2就是错误的。
// 例2
#include <string.h>
void main()
{
char *s = "192.168.0.26"; // 与例1的唯一区别,字符串数组变成了字符串常量指针!!!
char *delim = ".";
char *p;
printf("%s ", strtok(s, delim));
while((p = strtok(NULL, delim)))
printf("%s ", p);
printf("\n");
}
所以如果输入是字符串常量指针的时候,是不能直接传递给strtok函数的第一个参数的,大家可以将这个字符串常量指针中的内容逐一拷贝到一个字符串数组中,再进行分解,不过这种方法效率比较低,所以并不建议这样使用,如果实在无法使用strtok函数进行字符串分解,那么可以使用其他的函数进行类似分解,比如使用strstr函数、strchr函数等。
- 使用注意事项3
对于strtok函数的第二个参数,即分隔符,要注意:包含在delim中的字符均可以作为分隔符,而非严格匹配。可以把delim理解为分隔符的集合。这一点是非常重要的!当然,我们在分解字符串的时候,很少使用多个分隔符。这也导致,很多人在写例子的时候只讨论了一个分隔符的情况。有更多的人在看例子的时候也就错误的认识了delim的作用。
- 使用注意事项4
如果strtok函数要分解的字符串的首字符就是分隔符,那么strtok函数会忽略第一个字符,直接从下一个分隔符算起。比如:".192.168.0.26",那么第一个字符'.'就会被忽略,分解后的第一个字符串就是"192"。
总之,strtok函数是一个看起来很简单,但是使用起来有很多需要注意的细节的函数,所以应该理解掌握,由于strtok函数并不是线程安全的,所以很多情况下并不再使用这个函数,而是由程序员实现自己的字符串分割函数,从而保证线程安全,不过,在Linux中定义了strtok_r函数,这个函数是strtok函数的线程安全版本,具体使用方法可以参考其他资料。