2012-01-03 6 views
3

Я пытаюсь создать простое приложение на C++. Это приложение должно читать из файла и отображать данные. Я написал функцию:Как преобразовать тип из const char * в char *

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"); 

Ошибка:

cannot convert from 'const char *' to 'char *'

Не могли бы вы сказать мне, как я могу справиться с этим?

ответ

3

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

+1

Чтобы решить вашу проблему, не смешивайте строки и массивы char. – mydogisbox

+5

Реальный ответ - не использовать strtok, как говорит Пол, но если вы действительно этого хотите, сделайте копию строки, например, с помощью strdup. Но не забудьте освободить память, когда закончите! –

11

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

+6

@whiteangel: Нет. Почему вы не используете документацию? Функциональность 'strtok' C широко документирована через Интернет, четко объясняя, что она имеет довольно сложное поведение, которое не является тем, как вы предполагаете. (Кстати, 'split' в Python устарел.) –

3

Вы не можете просто «преобразовать его» и забыть об этом. Указатель, который вы получаете от .c_str(), находится в только для чтения буфером. Вам нужно скопировать его в новый буфер для работы: в идеале, избегая использования устаревших функций, таких как strtok.

(я не совсем уверен, что вы делаете с этим токенизации, на самом деле,. Вы просто индексации в символы в один раз tokenised строки, не индексировать лексем)

Вы также запутанным динамическое и автоматическое хранение.

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

Спасибо, он почти работает ... но дает ошибку ошибки C2039: 'pushBack': не является членом 'std :: vector <_Ty>' – ruhungry

+1

Ах да, пропустил исправление этого. –

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 (который изменяет его параметр), IIRC недействителен C++ (вы можете отбросить константу, но вы не можете изменять объект const). Таким образом, он может работать для вашей конкретной платформы/компилятора или нет (и даже если он работает, он может разорваться в любое время).

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

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

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

Смежные вопросы