2012-01-03 18 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:いいえ。なぜドキュメントを使用していませんか? Cの 'strtok'機能は、インターネット上で広く文書化されています。あなたの想定していないようなかなり複雑な動作をしていることを明確に説明しています。 (ちなみに、Pythonの 'split'は非推奨です) –

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

ありがとう、それはほとんど動作します...しかし、エラーエラーC2039を与える: 'pushBack': 'std :: vector <_Ty>'のメンバーではありません – ruhungry

+1

ああ、訂正していません。 –

1

私はc_str()は、文字列の内容への読み取り専用のポインタを与えるので、これは

char * line2 = line.c_str(); 

、エラーが前の行の上に実際にあると思います。 C++文字列から変更可能なCスタイルの文字列を取得する標準的な方法はありません。そして、あなたが本当にstrtokを使用したい場合は

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

、:

(それはあなたがする抱き合わせているものだと仮定して)文字列からスペースで区切られた単語を読むための最も簡単なオプションは、文字列ストリームを使用することですCスタイルのターミネータを使用して、書込み可能な文字列のコピーが必要です。これを実行するための1つの方法は、ベクターにそれをコピーすることである:心の中

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

あなたはそれを求めているので:

を理論的にあなたがchar*を取得するためにconst_cast<char*>(line.c_str())を使用することができます。しかし、この結果をstrtok(そのパラメータを変更する)に与えることは、IIRCは有効ではありません。++(constオブジェクトをキャストしても構いませんが、constオブジェクトは変更できません)。だからあなたの特定のプラットフォーム/コンパイラで動作するかもしれません(そしてそれが動作しても、いつでも中断するかもしれません)。

他の方法は、文字列(とmodifyable)の内容物を充填されたコピーを作成することです。もちろん

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

他の回答が非常に詳細にあなたを伝えるように、あなたは本当に避けなければなりませんstrtokのような関数をC++で直接使用している場合は、std::stringを直接操作することをお勧めします(少なくとも、C++、高性能の要件を熟知していない限りはc-api関数を使用すると、 )。

関連する問題