如何将const char *类型转换为char *类型

4

我希望创建一个简单的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 *”

您能告诉我如何处理它吗?

5个回答

11

不要使用strtokstd::string有自己的字符串扫描函数,例如find


6
@whiteangel: 不行。为什么你不使用文档?C语言中的strtok功能在互联网上有广泛的文献资料,清楚地解释了它具有相当复杂的行为,这与你的假设不同。(顺便说一下,Python中的split已被弃用。) - Lightness Races in Orbit

3

要使用strtok函数,需要一个可写的字符串副本。而c_str()函数返回的是只读指针。


5
答案不是使用strtok,正如Paul所说的那样,但如果你真的想用,可以使用strdup复制字符串。但不要忘记在完成后释放内存! - Mr Lister

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;
}

谢谢,它几乎可以工作...但是出现了错误C2039: 'pushBack':不是'std :: vector <_ Ty>'的成员。 - ruhungry

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的使用相当困难;您需要为每个标记调用它一次,而不是一次创建标记数组,并确保在您完成字符串后没有其他内容(例如另一个线程)调用它。我不确定我的代码是否完全正确;我很久以前就没试过使用这种特殊的恶魔形式了。

1

既然你要求了:

理论上,你可以使用const_cast<char*>(line.c_str())来获取一个char*。但是将其结果传递给strtok(它修改其参数)在我记得不是有效的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函数更快(通过分析))。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接