Как преобразовать тип из const char * в char * - PullRequest
3 голосов
/ 03 января 2012

Я пытаюсь создать простое приложение на 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 голосов
/ 03 января 2012

Не используйте strtok.std::string имеет свои собственные функции для сканирования строк, например, find.

3 голосов
/ 03 января 2012

Вы не можете просто "преобразовать это" и забыть об этом. Указатель, который вы получаете от .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 голосов
/ 03 января 2012

Чтобы использовать strtok, вам понадобится записываемая копия строки. c_str () возвращает указатель только для чтения.

1 голос
/ 03 января 2012

Так как вы просили об этом:

Теоретически вы можете использовать const_cast<char*>(line.c_str()), чтобы получить char*. Однако предоставление результата для strtok (который изменяет его параметр) является IIRC недопустимым c ++ (вы можете отбросить константность, но вы не можете модифицировать константный объект). Так что он может работать для вашей конкретной платформы / компилятора или нет (и даже если он работает, он может сломаться в любое время).

Другой способ - создать копию, которая заполнена содержимым строки (и может быть изменена):

std::vector<char> tmp_str(line.begin(), line.end());
myLine = strtok(&tmp_str[0],"\t");

Конечно, как другие ответы говорят вам очень подробно, вам действительно следует избегать использования таких функций, как strtok в c ++, в пользу функциональности, работающей непосредственно на std::string (по крайней мере, если вы не обладаете твердым пониманием c ++, Требования к производительности и знают, что использование функции c-api быстрее в вашем конкретном случае (через профилирование)).

1 голос
/ 03 января 2012

Я подозреваю, что ошибка действительно в предыдущей строке,

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 довольно сложно правильно использовать; вам нужно вызывать его один раз для каждого токена, а не один раз, чтобы создать массив токенов, и убедиться, что ничто другое (например, другой поток) не вызывает его, пока вы не закончите со строкой. Я не уверен, что мой код полностью верен; Я давно не пытался использовать именно эту форму зла.

...