繁体   English   中英

为什么 strtok 采用 char* 而不是 const char*?

[英]Why strtok takes a char* and not a const char*?

据我所知, strtok()不会修改底层字符串,那么为什么不使用 const char*指针而不是const char*指针呢? 此外,在标记化时,您不希望字符串更改,对吗?

更新: https ://godbolt.org/z/3SPvRB 很明显 strtok() 确实修改了底层字符串。 非变异标记器的替代方案是什么?

但是strtok确实会更改字符串。

取以下代码:

char sz[] = "The quick brown fox";
char* token = strtok(sz, " ");

它会将数组的内容更改为:

"The\0quick brown fox";

第一个发现的分隔符被替换为空字符。 在内部(通过线程本地存储或全局变量),指向发现的分隔符之后的下一个字符的指针被存储,以便随后对strtok(NULL, " ")调用将从原始字符串中解析下一个标记。

它确实修改了底层字符串。 请参阅: http : //www.cplusplus.com/reference/cstring/strtok/

标记的这一结尾会自动替换为空字符,并且标记开头由函数返回。

证明:

/* strtok example */
#include <stdio.h>
#include <string.h>

int main ()
{
  char str[] ="- This, a sample string.";
  char * pch;
  printf ("Splitting string \"%s\" into tokens:\n",str);
  pch = strtok (str," ,.-");
  while (pch != NULL)
  {
    printf ("%s\n",pch);
    pch = strtok (NULL, " ,.-");
  }

  /* note this line... */
  printf ("str = \"%s\"\n",str);
  return 0;
}

印刷:

Splitting string "- This, a sample string." into tokens:
This
a
sample
string
str = "- This"

更新: https : strtok()很明显strtok()确实修改了底层字符串。 非变异标记器的替代方案是什么?

如评论中所述,您可以:

  1. 制作原始字符串的副本,然后使用strtok()标记副本; 或者
  2. 编写自己的实现,将令牌括起来并将令牌复制到新存储:
    • 使用 C strspn向前扫描到第一个非分隔符字符,这将是令牌的开头,然后使用strcspn向前扫描到标记令牌结尾的下一个分隔符,
    • 用一对指针手动做同样的事情; 或者
    • 对于 C++11 或更高版本,您可以使用.find_first_not_of()向前扫描到第一个非分隔符字符,然后使用.find_first_of()来定位标记.find_first_of()的分隔符。

在每种情况下,您都将把标记字符复制到一个新字符串(使用memcpy进行 C 类型实现——不要忘记nul-terminate )或 C++11 只需使用.substr()成员函数。

一个非常基本的 C++11 实现看起来类似于:

std::vector<std::string> stringtok (const std::string& s, const std::string& delim)
{
    std::vector<std::string> v {};  /* vector of strings for tokens */
    size_t beg = 0, end = 0;        /* begin and end positons in str */

    /* while non-delimiter char found */
    while ((beg = s.find_first_not_of (delim, end)) != std::string::npos) {
        end = s.find_first_of (delim, beg);       /* find delim after non-delim */
        v.push_back (s.substr (beg, end - beg));  /* add substr to vector */
        if (end == std::string::npos)             /* if last delim, break */
            break;
    }

    return v;   /* return vector of tokens */
}

如果您遵循逻辑,它会准确跟踪函数定义上面描述的内容。 将其组合成一个简短的示例,您将拥有:

#include <iostream>
#include <string>
#include <vector>

std::vector<std::string> stringtok (const std::string& s, const std::string& delim)
{
    std::vector<std::string> v {};  /* vector of strings for tokens */
    size_t beg = 0, end = 0;        /* begin and end positons in str */

    /* while non-delimiter char found */
    while ((beg = s.find_first_not_of (delim, end)) != std::string::npos) {
        end = s.find_first_of (delim, beg);       /* find delim after non-delim */
        v.push_back (s.substr (beg, end - beg));  /* add substr to vector */
        if (end == std::string::npos)             /* if last delim, break */
            break;
    }

    return v;   /* return vector of tokens */
}

int main (void) {

    std::string str = "    my           dog   has    fleas      ",
                delim = " ";
    std::vector<std::string> tokens;

    tokens = stringtok (str, delim);

    std::cout << "string: '" << str << "'\ntokens:\n";
    for (auto s : tokens)
        std::cout << "  " << s << '\n';
}

示例使用/输出

$ ./bin/stringtok
string: '    my           dog   has    fleas      '
tokens:
  my
  dog
  has
  fleas

注意:这只是实现不修改原始字符串标记化的众多方法之一。 仔细检查一下,如果您还有其他问题,请告诉我。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM