1

文字列をさまざまなセクションに分割して解析する関数がありますが、文字列を char* に変換すると、不正な形式の出力が得られます。

int parseJob(char * buffer)
{ // Parse raw data, should return individual jobs
    const char* p;
    int rows = 0;
    for (p = strtok( buffer, "~" );  p;  p = strtok( NULL, "~" )) { 
        string jobR(p);
        char* job = &jobR[0];
        parseJobParameters(job); // At this point, the data is still in good condition
    }
    return (1);
}

int parseJobParameters(char * buffer)
{ // Parse raw data, should return individual job parameters
    const char* p;
    int rows = 0;
    for (p = strtok( buffer, "|" );  p;  p = strtok( NULL, "|" )) { cout<<p; } // At this point, the data is malformed.
    return (1);
}

最初の関数が 2 番目の関数を呼び出す間に何が起こるかはわかりませんが、データの形式が正しくありません。

与えられたコード例からわかるように、string を char* に変換する同じメソッドが使用され、正常に動作します。

私は Visual Studio 2012/C++ を使用しています。ガイダンスとコード例は大歓迎です。

4

3 に答える 3

2

std::stringコードが機能しない「物理的な」理由は、C++とは何の関係もありません。純粋なCでも機能しません。strtokは、中間の解析状態をグローバル変数に格納する関数です。strtokこれはすぐに、一度に複数の文字列を解析するために使用できないことを意味します。最初の解析セッションを終了する前に2番目の解析セッションを開始すると、最初の解析セッションによって保存された内部データが上書きされるため、修復できないほど台無しになります。つまり、strtok解析セッションは重複してはなりません。あなたのコードでは、それらは重複しています。


また、C ++ 03では、直接で使用するという考えはstd::string最初strtokから運命づけられています。に格納されている内部シーケンスstd::stringは、nullで終了することが保証されていません。これは、通常&jobR[0]、C文字列ではないことを意味します。と一緒に使用することはできませんstrtokstd::stringをC文字列に変換するには、を使用する必要がありますc_str()。ただし、によって返されるC文字列はc_str()変更できません。

C ++ 11では、null終端は演算子を介して表示されるはずですが[]、実際の文字列と連続してターミネータオブジェクトを格納する必要はないよう&jobR[0]です。したがって、C++でもC文字列ではありません。 11.11。c_str()またはによって返されるC文字列はdata()変更できません。

于 2012-12-25T21:15:32.720 に答える
2

strtok()あなたがしているように、同時に複数の文字列を解析するために使用することはできません。parseJobParameters()の最初のループ反復での最初の呼び出しは、を指すparseJob()内部バッファを変更するため、の2番目のループ反復は元のデータを処理しなくなります。ネストされた呼び出しを使用しないようにコードを書き直す必要があります。例:strtok()parseJob()strtok()

#include <vector>
#include <string>

void split(std::string s, const char *delims, std::vector &vec)
{
    // alternatively, use s.find_first_of() and s.substr() instead...
    for (const char* p = strtok(s.c_str(), delims); p != NULL; p = strtok(NULL, delims))
    {
         vec.push_back(p);
    }
}

int parseJob(char * buffer)
{
    std::vector<std::string> jobs;
    split(buffer, "~", jobs);
    for (std::vector<std::string>::iterator i = jobs.begin(); i != jobs.end(); ++i)
    {
        parseJobParameters(i->c_str());
    }
    return (1);
}

int parseJobParameters(char * buffer)
{
    std::vector<std::string> params;
    split(buffer, "|", params);
    for (std::vector<std::string>::iterator i = params.begin(); i != params.end(); ++i)
    {
        std::cout << *i;
    }
    return (1);
}
于 2012-12-25T20:37:53.223 に答える
0

これにより string の最初の文字のアドレスがchar* job = &jobR[0];得られますが、有効な C スタイルの文字列は得られません。あなたは使うべきですchar* job = jobR.c_str();

それがあなたの問題を解決すると確信していますが、もちろん、buffer渡された を読む方法にも問題がある可能性がありparseJobます。

編集: もちろん、strtok を使用する関数からも strtok を呼び出しています。内部 strtok は次のようになります。

char *strtok(char *str, char *separators)
{
     static char *last;
     char *found = NULL; 

     if (!str) str = last;
     ... do searching for needle, set found to beginning of non-separators ... 
     if (found) 
     {
          *str = 0; // mark end of string. 
     }

     last = str;
     return found;
}

を呼び出すと「last」が上書きされるため、 に戻ったときにparseParameters使用できませんstrtok(NULL, ... )parseJobs

于 2012-12-25T20:10:47.390 に答える