strtok() - 为什么你必须传递NULL指针才能获取字符串中的下一个标记?

24

这是strtok()的解释。

#include <string.h>
char* strtok( char* s1, 
              const char* s2 );*
第一次调用 strtok() 返回指向 s1 指向的字符串中第一个标记的指针。为了获取字符串中的下一个标记,后续调用 strtok() 必须将第一个参数传递为 NULL 指针。但我不知道为什么必须传递 NULL 指针才能获取字符串中的下一个标记。我在互联网上搜索了大约 15 分钟,但没有找到解释。

1
如果代码没有通过NULL,那么代码应该传递什么来继续对同一字符串进行标记化? - chux - Reinstate Monica
我猜这只是为了让你选择在不跟踪下一个标记的位置的情况下一次性放弃对整个字符串进行标记化。如果这是现在设计的C ++,它很可能会不同。 - chris
1
你的搜索中没有看到 http://www.cplusplus.com/reference/cstring/strtok/ 吗? - Jongware
3
因为40年前它的设计就是这样的。设计不佳,单线程和单用途(不可嵌套),而非提供上下文对象。 - user207421
1
我正在寻找的单词是“非可重入”的。 - user207421
2个回答

43

strtok()通过使用静态变量来保留一些数据,从而可以在上一次调用时离开的地方继续搜索。如果你想让strtok()继续搜索同一个字符串,你需要将一个NULL指针作为它的第一个参数传递给它。strtok()会检查第一个参数是否为NULL,如果是,则使用其当前存储的数据。如果第一个参数不是null,则视为新搜索,并重置所有内部数据。

也许你可以搜索一个实际的strtok()函数实现来了解如何处理这个NULL参数。我找到了一个很小的实现,足以在此处发布,这样你就能够有一个基本的思路:

/* Copyright (c) Microsoft Corporation. All rights reserved. */

#include <string.h>

/* ISO/IEC 9899 7.11.5.8 strtok. DEPRECATED.
 * Split string into tokens, and return one at a time while retaining state
 * internally.
 *
 * WARNING: Only one set of state is held and this means that the
 * WARNING: function is not thread-safe nor safe for multiple uses within
 * WARNING: one thread.
 *
 * NOTE: No library may call this function.
 */

char * __cdecl strtok(char *s1, const char *delimit)
{
    static char *lastToken = NULL; /* UNSAFE SHARED STATE! */
    char *tmp;

    /* Skip leading delimiters if new string. */
    if ( s1 == NULL ) {
        s1 = lastToken;
        if (s1 == NULL)         /* End of story? */
            return NULL;
    } else {
        s1 += strspn(s1, delimit);
    }

    /* Find end of segment */
    tmp = strpbrk(s1, delimit);
    if (tmp) {
        /* Found another delimiter, split string and save state. */
        *tmp = '\0';
        lastToken = tmp + 1;
    } else {
        /* Last segment, remember that. */
        lastToken = NULL;
    }

    return s1;
}

4
非常感谢,现在我明白了! - phez1
警告:只有一个状态集被保留,这意味着该函数既不是线程安全的,也不适用于在同一线程中多次使用。 - Minh Tran
@MinhTran 这意味着该函数不应在多线程调用中使用,因为静态变量可能会被其他线程更改。请参见 /* UNSAFE SHARED STATE! */ - thangdc94

13
如果您传递一个非NULL值,那么您正在请求开始对不同的字符串进行标记化。
如果您传递了一个NULL值,则是要求继续对之前相同的内容进行标记化。

1
但是,strtok如何知道它是相同的字符串呢? 现在你传递NULL,但那不是字符串的地址。 - phez1
7
它一次只能处理一个字符串并保持内部状态,这会导致各种问题。 - chris

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接