可能有人给我解释一下什么样的差异之间存在着strtok()和strsep()?它们的优点和缺点是什么?为什么我会选择一个而不是另一个.
Jon*_*ler 44
之间的一个主要区别strtok(),并strsep()是strtok()被标准化(C标准,并因此也通过POSIX),但strsep()不规范(由C或POSIX;它是GNU C库中可用的,和起源于BSD).因此,可移植的代码更容易使用strtok()比strsep().
另一个区别是strsep()对不同字符串上的函数的调用可以是交错的,而你不能这样做strtok()(尽管你可以strtok_r()).因此,strsep()在库中使用不会意外破坏其他代码,而strtok()在库函数中使用必须记录,因为strtok()同时使用的其他代码不能调用库函数.
该手册strsep()在kernel.org说:
引入strsep()函数作为strtok(3)的替代,因为后者无法处理空字段.
因此,另一个主要区别是GeorgeGaál在他的回答中强调的那个; strtok()允许在单个标记之间使用多个分隔符,而strsep()期望标记之间使用单个分隔符,并将相邻分隔符解释为空标记.
双方strsep()并strtok()修改其输入字符串,既不让你识别哪些分隔符标志着令牌结束(因为这两个写一个NUL '\0'令牌结束后在分离器).
strsep()在需要空令牌时使用,而不是在令牌之间允许多个分隔符,并且在您不介意可移植性时使用.strtok_r(),当你想允许标记之间的多个分隔符,你不想空标记(和POSIX足够的便携式你).strtok()如果你不这样做,你只会在有人威胁你的生命时使用.而你只能用它足够长的时间让你摆脱危及生命的境地; 然后你会再次放弃使用它.它有毒; 不要使用它.编写自己的strtok_r()或者strsep()使用它会更好strtok().strtok()有毒?strtok()如果在库函数中使用,该函数是有毒的.如果您的库函数使用strtok(),则必须清楚地记录.
那是因为:
strtok()并调用也使用的函数strtok(),则会中断调用函数.strtok(),那将破坏你的函数的使用strtok().strtok()在任何给定时间最多只能有一个线程使用- 跨越一系列strtok()调用.此问题的根源是调用之间保存的状态,允许strtok()在停止的位置继续.除了"不要使用strtok()" 之外,没有合理的方法来解决问题.
strsep()如果可用,您可以使用.strtok_r()如果可用).strtok_s()如果可用,您可以使用Microsoft .strtok_s(),但其界面strtok_r()与微软的界面不同strtok_s().BSD strsep():
char *strsep(char **stringp, const char *delim);
Run Code Online (Sandbox Code Playgroud)
POSIX strtok_r():
char *strtok_r(char *restrict s, const char *restrict sep, char **restrict state);
Run Code Online (Sandbox Code Playgroud)
微软strtok_s():
char *strtok_s(char *strToken, const char *strDelimit, char **context);
Run Code Online (Sandbox Code Playgroud)
附件K strtok_s():
char *strtok_s(char * restrict s1, rsize_t * restrict s1max,
const char * restrict s2, char ** restrict ptr);
Run Code Online (Sandbox Code Playgroud)
请注意,这有4个参数,而不是其他两个变体中的3个参数strtok().
在第一差strtok()和strsep()为他们处理输入字符串的连续分隔符的方式。
连续分隔符字符处理方式strtok():
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main(void) {
const char* teststr = "aaa-bbb --ccc-ddd"; //Contiguous delimiters between bbb and ccc sub-string
const char* delims = " -"; // delimiters - space and hyphen character
char* token;
char* ptr = strdup(teststr);
if (ptr == NULL) {
fprintf(stderr, "strdup failed");
exit(EXIT_FAILURE);
}
printf ("Original String: %s\n", ptr);
token = strtok (ptr, delims);
while (token != NULL) {
printf("%s\n", token);
token = strtok (NULL, delims);
}
printf ("Original String: %s\n", ptr);
free (ptr);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
输出:
# ./example1_strtok
Original String: aaa-bbb --ccc-ddd
aaa
bbb
ccc
ddd
Original String: aaa
Run Code Online (Sandbox Code Playgroud)
在输出中,你可以看到令牌"bbb"和"ccc"一个又一个。strtok() 不表示出现连续的分隔符。另外,strtok() 修改输入字符串。
连续分隔符字符处理方式strsep():
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main(void) {
const char* teststr = "aaa-bbb --ccc-ddd"; //Contiguous delimiters between bbb and ccc sub-string
const char* delims = " -"; // delimiters - space and hyphen character
char* token;
char* ptr1;
char* ptr = strdup(teststr);
if (ptr == NULL) {
fprintf(stderr, "strdup failed");
exit(EXIT_FAILURE);
}
ptr1 = ptr;
printf ("Original String: %s\n", ptr);
while ((token = strsep(&ptr1, delims)) != NULL) {
if (*token == '\0') {
token = "<empty>";
}
printf("%s\n", token);
}
if (ptr1 == NULL) // This is just to show that the strsep() modifies the pointer passed to it
printf ("ptr1 is NULL\n");
printf ("Original String: %s\n", ptr);
free (ptr);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
输出:
# ./example1_strsep
Original String: aaa-bbb --ccc-ddd
aaa
bbb
<empty> <==============
<empty> <==============
ccc
ddd
ptr1 is NULL
Original String: aaa
Run Code Online (Sandbox Code Playgroud)
在输出中,你可以看到两个空字符串(指示通过<empty>之间)bbb和ccc。这两个空字符串用于"--"between"bbb"和"ccc"。当strsep()找到一个分隔符' '后"bbb",它替换分隔符'\0'字符并返回"bbb"。在此之后,strsep()找到了另一个分隔符'-'。然后它用字符替换分隔符'\0'并返回空字符串。下一个分隔符也是如此。
当strsep()返回指向空字符(即值为 的字符'\0')的指针时,将指示连续的分隔符字符。
该strsep() 修改输入字符串以及指针,其地址作为第一个参数传递strsep()。
第二个区别是,strtok()依赖于静态变量来跟踪字符串中的当前解析位置。此实现需要在开始第二个字符串之前完全解析一个字符串。但情况并非如此strsep()。
strtok()当另一个strtok()未完成时调用:
#include <stdio.h>
#include <string.h>
void another_function_callng_strtok(void)
{
char str[] ="ttt -vvvv";
char* delims = " -";
char* token;
printf ("Original String: %s\n", str);
token = strtok (str, delims);
while (token != NULL) {
printf ("%s\n", token);
token = strtok (NULL, delims);
}
printf ("another_function_callng_strtok: I am done.\n");
}
void function_callng_strtok ()
{
char str[] ="aaa --bbb-ccc";
char* delims = " -";
char* token;
printf ("Original String: %s\n", str);
token = strtok (str, delims);
while (token != NULL)
{
printf ("%s\n",token);
another_function_callng_strtok();
token = strtok (NULL, delims);
}
}
int main(void) {
function_callng_strtok();
return 0;
}
Run Code Online (Sandbox Code Playgroud)
输出:
# ./example2_strtok
Original String: aaa --bbb-ccc
aaa
Original String: ttt -vvvv
ttt
vvvv
another_function_callng_strtok: I am done.
Run Code Online (Sandbox Code Playgroud)
该函数function_callng_strtok()只打印标记"aaa",不打印输入字符串的其余标记,因为它会调用another_function_callng_strtok()它,然后调用strtok()它,strtok()并NULL在完成提取所有标记时设置 的静态指针。控制返回function_callng_strtok() while循环,由于指向的静态指针strtok()返回,这使得循环条件和循环退出。NULLNULLfalse
strsep()当另一个strsep()未完成时调用:
#include <stdio.h>
#include <string.h>
void another_function_callng_strsep(void)
{
char str[] ="ttt -vvvv";
const char* delims = " -";
char* token;
char* ptr = str;
printf ("Original String: %s\n", str);
while ((token = strsep(&ptr, delims)) != NULL) {
if (*token == '\0') {
token = "<empty>";
}
printf("%s\n", token);
}
printf ("another_function_callng_strsep: I am done.\n");
}
void function_callng_strsep ()
{
char str[] ="aaa --bbb-ccc";
const char* delims = " -";
char* token;
char* ptr = str;
printf ("Original String: %s\n", str);
while ((token = strsep(&ptr, delims)) != NULL) {
if (*token == '\0') {
token = "<empty>";
}
printf("%s\n", token);
another_function_callng_strsep();
}
}
int main(void) {
function_callng_strsep();
return 0;
}
Run Code Online (Sandbox Code Playgroud)
输出:
# ./example2_strsep
Original String: aaa --bbb-ccc
aaa
Original String: ttt -vvvv
ttt
<empty>
vvvv
another_function_callng_strsep: I am done.
<empty>
Original String: ttt -vvvv
ttt
<empty>
vvvv
another_function_callng_strsep: I am done.
<empty>
Original String: ttt -vvvv
ttt
<empty>
vvvv
another_function_callng_strsep: I am done.
bbb
Original String: ttt -vvvv
ttt
<empty>
vvvv
another_function_callng_strsep: I am done.
ccc
Original String: ttt -vvvv
ttt
<empty>
vvvv
another_function_callng_strsep: I am done.
Run Code Online (Sandbox Code Playgroud)
在这里你可以看到,strsep()在完全解析一个字符串之前调用没有任何区别。
因此,的缺点strtok(),并strsep()为这两个修改输入字符串,但strsep()拥有几个优点strtok()之上,如图所示。
从strsep:
strsep() 函数旨在替代 strtok() 函数。虽然 strtok() 函数出于可移植性的原因应该是首选(它符合 ISO/IEC 9899:1990 (``ISO C90'')),但它无法处理空字段,即检测由两个相邻分隔符分隔的字段,或一次用于多个字符串。strsep() 函数首次出现在 4.4BSD 中。
以供参考:
| 归档时间: |
|
| 查看次数: |
21091 次 |
| 最近记录: |