如何在 char* 上使用 strtok

How to use strtok on char*

在 c++ 中,要使用 strtok 过滤掉分隔符,源必须是字符数组,否则会出现段错误。如何在指向 char 的指针上使用 strtok

如何构造的代码示例 strtok:

#include <stdio.h>
#include <string.h>

int main () {
  char str[] ="- This, a sample string."; // this is the string i want to split. notice how it's an array
  char * pch;
  pch = strtok (str," ,.-");
  while (pch != NULL)
  {
    printf ("%s\n",pch);
    pch = strtok (NULL, " ,.-");
  }
  return 0;
}

我想做的事的例子:

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

int main ()
{
  char* str ="- This, a sample string."; // since this is a pointer to char, it gives a segmentation fault after compiling, and executing.
  char * pch;
  pch = strtok (str," ,.-");
  while (pch != NULL)
  {
    printf ("%s\n",pch);
    pch = strtok (NULL, " ,.-");
  }
  return 0;
}

您正在尝试修改字符串文字(函数 strtok 更改源字符串插入空字符 '[=20=]'

char* str ="- This, a sample string.";

首先,在 C++ 中,与 C 字符串文字相对的是常量字符数组类型。所以你必须用限定符 const.

在 C++ 程序中编写指针的声明
const char* str ="- This, a sample string.";

在 C 和 C++ 中更改字符串文字的任何尝试都会导致未定义的行为。

例如在 C 标准中有这样写的 (6.4.5 String literals)

7 It is unspecified whether these arrays are distinct provided their elements have the appropriate values. If the program attempts to modify such an array, the behavior is undefined.

因此,在 C 中使用限定符 const.

声明指向字符串文字的指针总是更好

您可以使用例如 C 标准字符串函数 strspnstrcspn.

而不是 strtok

这是一个演示程序。

#include <iostream>
#include <iomanip>
#include <string_view>
#include <cstring>

int main()
{
    const char *s = "- This, a sample string.";
    const char *delim = " ., -";

    for (const char *p = s; *( p += strspn( p, delim ) ) != '[=12=]'; )
    {
        auto n = strcspn( p, delim );

        std::string_view sv( p, n );

        std::cout << std::quoted( sv ) << ' ';

        p += n;
    }

    std::cout << '\n';
}

程序输出为

"This" "a" "sample" "string"

例如,您可以声明一个字符串视图向量,如 std::vector<std::string_view> 并将每个子字符串存储在其中。

例如

#include <iostream>
#include <iomanip>
#include <string_view>
#include <vector>
#include <cstring>

int main()
{
    const char *s = "- This, a sample string.";
    const char *delim = " ., -";

    std::vector<std::string_view> v;

    for (const char *p = s; *( p += strspn( p, delim ) ) != '[=14=]'; )
    {
        auto n = strcspn( p, delim );

        v.emplace_back( p, n );

        p += n;
    }

    for (auto sv : v)
    {
        std::cout << std::quoted( sv ) << ' ';
    }
    std::cout << '\n';
}

程序输出同上图

或者,如果编译器不支持 C++ 17,那么您可以使用 std::vector<std::pair<const char *, size_t>>.

类型的向量来代替 std::vector<std::string_view> 类型的向量

例如

#include <iostream>
#include <iomanip>
#include <utility>
#include <vector>
#include <cstring>

int main()
{
    const char *s = "- This, a sample string.";
    const char *delim = " ., -";

    std::vector<std::pair<const char *, size_t>> v;

    for (const char *p = s; *( p += strspn( p, delim ) ) != '[=15=]'; )
    {
        auto n = strcspn( p, delim );

        v.emplace_back( p, n );

        p += n;
    }

    for (auto p : v)
    {
        std::cout.write( p.first, p.second ) << ' ';
    }
    std::cout << '\n';
}

程序输出为

This a sample string

或者您可以使用类型为 std::string 的对象向量:std::vector<std::string>.

在 C 中,您可以使用可变长度数组或动态分配的数组,其元素类型为结构类型,包含两个类型为 const char *size_t 的数据成员,类似于 C++ class std::pair。但是要定义数组,您首先需要使用相同的 for 循环计算字符串文字中有多少个单词。

这里是一个C演示程序。

#include <stdio.h>
#include <string.h>

int main( void )
{
    const char *s = "- This, a sample string.";
    const char *delim = " ., -";

    size_t nmemb = 0;

    for (const char *p = s; *( p += strspn( p, delim ) ) != '[=17=]'; )
    {
        ++nmemb;
        size_t n = strcspn( p, delim );
        p += n;
    }    

    struct SubString
    {
        const char *pos;
        size_t size;
    } a[nmemb];

    size_t i = 0;

    for (const char *p = s; *( p += strspn( p, delim ) ) != '[=17=]'; )
    {
        size_t n = strcspn( p, delim );

        a[i].pos = p;
        a[i].size =n;
        ++i;
        p += n;
    }

    for ( i = 0; i < nmemb; i++ )
    {
        printf( "%.*s ", ( int )a[i].size, a[i].pos );
    } 

    putchar( '\n' );   
}

程序输出为

This a sample string

Example of what I want to do:

char* str ="- This, a sample string."

您不能为所欲为,因为在 C++ 中,字符串文字不能隐式转换为指向 non-const char 的指针。此外,strtok 修改参数字符串,并且在 C++ 中不得修改 srtring 文字。

How to use strtok on c++ on char*

如果你真的想,你可以这样做:

char str_arr[] ="- This, a sample string.";
char* str = str_arr;

但是毫无意义


为了在不将字符串文字复制到可修改数组中的情况下对其进行标记化,您不得使用 strtok.