我从strtok和strtrok_r函数中获得了意外行为:
queue<string> tks;
char line[1024];
char *savePtr = 0;
while(true)
{
//get input from user store in line
tks.push(strtok_r(line, " \n", &savePtr)); //initial push only works right during first loop
char *p = nullptr;
for (...)
{
p = strtok_r(NULL, " \n", &savePtr);
if (p == NULL)
{
break;
}
tks.push(p);
}
delete p;
savePtr = NULL;
//do stuff, clear out tks before looping again
}
我尝试过使用strtok
并意识到在第二次循环中,初始推送没有发生。我试图使用可重入版本strtok_r
来控制保存的指针在第二个循环期间指向的内容,确保它在循环之前为空。
tks
仅在第一次循环中正确填充 - 后续循环根据line
我在这里缺少什么?
答案 0 :(得分:3)
只关注内循环并砍掉我认为不必要的所有东西。
#include <iostream>
#include <queue>
#include <string>
#include <cstring>
using namespace std;
int main()
{
std::queue<std::string> tks;
while(true)
{
char line[1024];
char *savePtr;
char *p;
cin.getline(line, sizeof(line));
p = strtok_r(line, " \n", &savePtr); // initial read. contents of savePtr ignored
while (p != NULL) // exit when no more data, which includes an emtpy line
{
tks.push(p); // got data, store it
p = strtok_r(NULL, " \n", &savePtr); // get next token
}
// consume tks
}
}
我喜欢在他的回答中使用Toby Speight使用的for循环的while循环,因为我觉得它更透明,更容易阅读。你的旅费可能会改变。当编译器完成它时,它们将完全相同。
无需删除任何内存。它都是静态分配的。除了tks
之外,没有必要在下一轮之前清除任何内容。 savePtr
将重置strtok_r
。
如果用户在一行上输入超过1024个字符,则会出现故障,但这不会崩溃。如果仍然无效,请查看您的消费方式tks
。它没有发布,所以我们无法排除故障。
如果可能,全心全意地建议更改为基于字符串的解决方案。这是一个非常简单,易于编写但速度慢的一个:
#include <iostream>
#include <queue>
#include <string>
#include <sstream>
int main()
{
std::queue<std::string> tks;
while(true)
{
std::string line;
std::getline(std::cin, line);
std::stringstream linestream(line);
std::string word;
// parse only on ' ', not on the usual all whitespace of >>
while (std::getline(linestream, word, ' '))
{
tks.push(word);
}
// consume tks
}
}
答案 1 :(得分:2)
你的代码不会为我编译,所以我修复了它:
#include <iostream>
#include <queue>
#include <string>
#include <cstring>
std::queue<std::string> tks;
int main() {
char line[1024] = "one \ntwo \nthree\n";
char *savePtr = 0;
for (char *p = strtok_r(line, " \n", &savePtr); p;
p = strtok_r(nullptr, " \n", &savePtr))
tks.push(p);
// Did we read it correctly?
for (; tks.size() > 0; tks.pop())
std::cout << ">" << tks.front() << "<" << std::endl;
}
这会产生预期的输出:
>one<
>two<
>three<
所以问题不在于您发布的代码。
答案 2 :(得分:0)
如果您可以选择使用boost,请尝试使用此标记来标记字符串。当然,通过提供自己的字符串和分隔符。
#include <vector>
#include <boost/algorithm/string.hpp>
int main()
{
std::string str = "Any\nString\nYou want";
std::vector< std::string > results;
boost::split( results, str, boost::is_any_of( "\n" ) );
}