我需要将字符串转换为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);
}
}
相关question。
答案 0 :(得分:8)
使用strdup()
将const char *
返回的c_str()
复制到char *
(之后记得free()
)
请注意,strdup()
和free()
是C,而不是C ++,函数,您最好使用std::string
的方法。
需要第二个strtok_s()因为否则你的循环不会终止(token
的值不会改变)。
答案 1 :(得分:5)
正如丹尼尔所说,你可以选择
strdup(line.c_str());
这比我最初提出的strcpy更好,因为它分配了必要的空间
答案 2 :(得分:5)
您无法转换为char *
,因为这会允许您写入std::string
的内部缓冲区。为避免使std::string
的实现可见,不允许这样做。
而不是strtok
,尝试更多“类C ++”的方式来标记字符串。看到这个问题:
答案 3 :(得分:2)
strtok()
是一个设计糟糕的功能。检查您的文档,看看您是否有更好的文档。顺便说一句,在任何类型的线程环境中都不要使用strtok()
,除非你的文档特别说它是安全的,因为它在调用之间存储状态并修改它所调用的字符串。我认为strtok_s()
是一个更安全的版本,但它不会是一个非常安全的版本。
要将std::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
调用delete[] temp_line;
。不要使用temp_line,因为您希望在处理后strtok()
。
你可能认为这很多摆弄,但这就是{{1}}和亲戚通常需要的东西。
答案 4 :(得分:1)
strtok的工作原理如下:
首先从unril开始调用返回字符串,如果没有找到分隔符,则调用所有字符串:
token = strtok_s(con, "#", &next_token);
使用NULL进行第二次调用允许您继续解析相同的字符串以查找下一个分隔符:
token = strtok_s(NULL, "#", &next_token);
如果到达字符串的末尾,则下一次调用将返回NULL;
答案 5 :(得分: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());
}
答案 6 :(得分:0)
第二个strtok调用在循环内部。它会使您的令牌指针前进,以便您逐个打印出令牌,直到您打印出所有这些令牌,指针变为空并退出循环。
要回答你问题的第一部分,正如其他人所建议的那样,c_str()只给你内部缓冲区指针 - 你不能修改它,这就是为什么它是const。如果要修改它,则需要分配自己的缓冲区并将字符串的内容复制到其中。
答案 7 :(得分:0)
如果您确实需要访问字符串的内部缓冲区,请按以下方式进行操作:&*string.begin()
。
在某些情况下,直接访问字符串的缓冲区非常有用,here您可以看到这种情况。
答案 8 :(得分: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;
}
答案 9 :(得分:-1)
我认为您可以先将字符串转换为const char *,然后将const char *复制到char *缓冲区以供进一步使用。