4

我需要将字符串转换为 char * 以在 strtok_s 中使用,但一直无法弄清楚。c_str() 转换为不兼容的 const char *。

另外,如果有人可以向我解释为什么第二个 strtok_s 函数(在循环内)是必要的,那将是一个很大的帮助。为什么我需要显式推进令牌,而不是例如它所在的 while 循环,它隐式地连续获取文件的每一行。

while( getline(myFile, line) ) { // Only one line anyway. . . is there a better way?
    char * con = line.c_str();
    token = strtok_s( con, "#", &next_token);
    while ((token != NULL))
    {
        printf( " %s\n", token );
        token = strtok_s( NULL, "#", &next_token);
    }
}

相关问题

4

10 回答 10

8

用于将返回的 bystrdup()复制到 a中(以后记住)const char *c_str()char *free()

请注意,strdup()andfree()是 C 而不是 C++ 函数,最好使用 of 方法std::string

需要第二个 strtok_s() ,否则您的循环将不会终止(token' 的值不会改变)。

于 2009-10-07T15:34:24.433 回答
5

正如丹尼尔所说,你可以去

strdup(line.c_str());

哪个比我最初提出的 strcpy 更好,因为它分配了必要的空间

于 2009-10-07T15:31:51.630 回答
5

您不能转换为 achar *因为那将允许您写入std::string的内部缓冲区。为了避免使std::string' 的实现可见,这是不允许的。

代替strtok,尝试一种更“类似 C++”的方式来标记字符串。看到这个问题:

如何在 C++ 中标记字符串?

于 2009-10-07T15:32:18.447 回答
2

strtok()是一个设计糟糕的功能。检查您的文档,看看您是否有更好的文档。顺便说一句,strtok()除非您的文档明确说明它是安全的,否则永远不要在任何类型的线程环境中使用,因为它会在调用之间存储状态并修改调用它的字符串。我认为strtok_s()这是一个更安全的版本,但它不会是一个真正安全的版本。

要将 astd::string转换为char *,您可以执行以下操作:

char * temp_line = new char[line.size() + 1];  // +1 char for '\0' terminator
strcpy(temp_line, line.c_str());

并使用temp_line. 您的安装可能有一个strdup()功能,它将复制上述内容。

您需要两次调用的原因strtok_s()是它们做不同的事情。第一个告诉strtok_s()它需要处理哪个字符串,第二个继续使用相同的字符串。这就是 NULL 参数的原因;它告诉strtok_s()继续使用原始字符串。

因此,您需要一次调用来获取第一个令牌,然后为每个后续令牌调用一次。它们可以与类似的东西结合使用

char * temp_string_pointer = temp_line;
while ((token = strtok_s( con, "#", &next_token)) != NULL)
{
   temp_string_pointer = NULL;

依此类推,因为这将strtok_s()使用字符串指针调用一次,然后使用NULL. 不要为此使用 temp_line,因为您想delete[] temp_line;在处理后使用。

您可能会认为这是很多摆弄,但这就是strtok()亲戚通常需要的。

于 2009-10-07T16:09:11.010 回答
1

只要你有一个std::string并且你需要的是一个(可修改的)字符数组,那么std::vector<char>你需要的是:

void f(char* buffer, std::size_t buffer_size);

void g(std::string& str)
{
  std::vector<char> buffer(str.begin(),str.end());
  // buffer.push_back('\0');    // use this if you need a zero-terminated string
  f(&buffer[0], buffer.size()); // if you added zero-termination, consider it for the size
  str.assign(buffer.begin(), buffer.end());
}
于 2009-10-07T15:45:50.150 回答
1

strtok 的工作原理是这样的:

如果没有找到分隔符,则首先调用从开始的返回字符串 unril 分隔符或所有字符串:

token = strtok_s(con, "#", &next_token);

使用 with NULL 的第二次调用允许您继续解析相同的字符串以查找下一个分隔符:

token = strtok_s(NULL, "#", &next_token);

如果到达字符串的末尾,下一次调用将返回 NULL;

于 2009-10-07T15:35:19.703 回答
0

如果你真的需要访问字符串的内部缓冲区,方法如下&*string.begin():直接访问字符串的缓冲区在某些情况下很有用,这里你可以看到这样的情况。

于 2009-10-07T15:54:42.190 回答
0

第二个 strtok 调用在循环内。它使您的令牌指针前进,以便您一个接一个地打印出令牌,直到您打印出所有令牌,指针变为空并退出循环。

为了回答您问题的第一部分,正如其他人所建议的那样, c_str() 只为您提供内部缓冲区指针 - 您无法修改它,这就是为什么它是 const 的。如果要修改它,则需要分配自己的缓冲区并将字符串的内容复制到其中。

于 2009-10-07T15:37:08.827 回答
0

您可以轻松编写一个转换例程来标记字符串并返回子字符串向量:

std::vector<std::string> parse(const std::string& str, const char delimiter)
{
    std::vector<std::string> r;

    if(str.empty())
        return r;

    size_t prev = 0, curr = 0;

    do
    {
        if(std::string::npos == (curr = str.find(delimiter, prev)))
            curr = str.length();

        r.push_back(str.substr(prev, curr - prev));
        prev = curr + 1;
    }
    while(prev < (int)str.length());
    return r;
}
于 2009-10-07T20:20:56.010 回答
-1

我认为您可以先将字符串转换为 const char*,然后将 const char* 复制到 char* 缓冲区以供进一步使用。

于 2009-10-07T15:33:53.170 回答