我正在尝试用C ++创建简单的应用程序。此应用程序必须从文件中读取并显示数据。我写了函数:
std::vector <AndroidApplication> AndroidApplication::getAllApp(){
std::vector<AndroidApplication> allApp;
std::fstream f;
f.open("freeApps.txt");
std::string line;
if(f.is_open()){
while(getline(f, line)) {
std::string myLine = "";
char * line2 = line.c_str();
myLine = strtok(line2,"\t");
AndroidApplication * tmpApp = new AndroidApplication(myLine[1], myLine[2], myLine[4]);
tmpApp->Developer = myLine[0];
tmpApp->Pop = myLine[3];
tmpApp->Type = myLine[5];
allApp->pushBack(tmpApp);
}
}
return allApp;
}
它引发了我的错误:
myLine = strtok(line2,"\t");
错误:
无法从'const char *'转换为'char *'
你能告诉我怎么处理它?</ p>
答案 0 :(得分:11)
请勿使用strtok
。 std::string
有自己的字符串扫描功能,例如find
。
答案 1 :(得分:3)
要使用strtok,您需要一个可写的字符串副本。 c_str()返回一个只读指针。
答案 2 :(得分:3)
你不能只是“转换它”而忘记它。从.c_str()
获得的指针是只读缓冲区。您需要将其复制到新的缓冲区中才能使用:理想情况下,首先要避免使用strtok
等过时的函数。
(实际上,我不太确定你在使用该标记化做什么;你只是在一次标记化的字符串中索引字符,而不是索引标记。)
您还混淆了动态和自动存储。
std::vector<AndroidApplication> AndroidApplication::getAllApp()
{
std::vector<AndroidApplication> allApp;
// Your use of fstreams can be simplified
std::fstream f("freeApps.txt");
if (!f.is_open())
return allApp;
std::string line;
while (getline(f, line)) {
// This is how you tokenise a string in C++
std::istringstream split(line);
std::vector<std::string> tokens;
for (std::string each;
std::getline(split, each, '\t');
tokens.push_back(each));
// No need for dynamic allocation here,
// and I'm assuming you wanted tokens ("words"), not characters.
AndroidApplication tmpApp(tokens[1], tokens[2], tokens[4]);
tmpApp.Developer = tokens[0];
tmpApp.Pop = tokens[3];
tmpApp.Type = tokens[5];
// The vector contains objects, not pointers
allApp.push_back(tmpApp);
}
return allApp;
}
答案 3 :(得分:1)
我怀疑错误实际上是在前一行,
char * line2 = line.c_str();
这是因为c_str()
给出了一个指向字符串内容的只读指针。没有标准的方法可以从C ++字符串中获取可修改的C风格字符串。
从字符串中读取空格分隔单词的最简单选项(假设您正在做的事情)是使用字符串流:
std::vector<std::string> words;
std::istringstream stream(line);
std::copy(std::istream_iterator<std::string>(stream),
std::istream_iterator<std::string>(),
back_inserter(words));
如果你真的想使用strtok
,那么你需要一个字符串的可写副本,带有C风格的终结符;一种方法是将其复制到矢量中:
std::vector<char> writable(line.c_str(), line.c_str() + line.length() + 1);
std::vector<char *> words;
while (char * word = strtok(words.empty() ? &writable[0] : NULL, " ")) {
words.push_back(word);
}
请记住strtok
很难正确使用;你需要为每个令牌调用一次,而不是一次创建一个令牌数组,并确保在你完成字符串之前没有其他任何东西(比如另一个线程)调用它。我不确定我的代码是完全正确的;我很久没有尝试过使用这种特殊形式的邪恶了。
答案 4 :(得分:1)
因为你要求它:
理论上,您可以使用const_cast<char*>(line.c_str())
来获取char*
。但是将结果赋予strtok
(修改其参数)是IIRC无效的c ++(你可能会抛弃constness,但你可能不会修改const对象)。所以它可能适用于您的特定平台/编译器(即使它工作也可能随时中断)。
另一种方法是创建一个副本,其中填充了字符串的内容(并且可以修改):
std::vector<char> tmp_str(line.begin(), line.end());
myLine = strtok(&tmp_str[0],"\t");
当然,正如其他答案非常详细地告诉你的那样,你真的应该避免在c ++中使用像strtok
这样的函数来支持直接在std::string
上工作的功能(至少除非你有一个牢固的把握)在c ++上,高性能要求和知道在特定情况下使用c-api函数会更快(通过分析)。