1

申し訳ありませんが、エラーを完全に再現できるバージョンを作成することは非常に困難です --- したがって、私の回路図コードを公開してください。

このプログラムは、Web ページから情報を取得して処理し、出力を ASCII ファイルに保存します。エラーなどを報告するための「ログ」ファイル(FILE *theLog--- オブジェクト内に含まれる)もあります。Manager


いくつかのバックグラウンド メソッド:

// Prints string to log file
void Manager::logEntry(const string lstr) {
    if( theLog != NULL ) { fprintf(theLog, "%s", lstr.c_str()); }
}

// Checks if file with given name already exists
bool fileExists(const string fname) {
    FILE *temp;
    if( temp = fopen(fname.c_str(), "r") ) { 
        fclose(temp);
        return true;
    } else { return false; }
}

// Initialize file for writing (some components omitted)...
bool initFile(FILE *&oFile, const string fname) {
    if(oFile = fopen(fname.c_str(), "w") ) { return true; }
    else { return false; }
}

トラブルの原因:

// Gets data from URL, saves to file 'dataFileName', input control flag 'foreCon'
//                     stu is some object that has string which i want
bool saveData(Manager *man, Stuff *stu, string dataFileName, const int foreCon) {
    char logStr[CHARLIMIT_LARGE];          // CHARLIMIT_LARGE = 2048
    sprintf(logStr, "Saving Data...\n");
    man->logEntry( string(logStr) );       // This appears fine in 'theLog' correctly

    string data = stu->getDataPrefixStr() + getDataFromURL() + "\n";        // fills 'data' with stuff
    data += stu->getDataSuffixStr();

    if( fileExists(dataFileName) ) {
        sprintf(logStr, "save file '%s' already exists.", dataFileName.c_str() );
        man->logEntry( string(logStr) );
        if( foreCon == -1 ) {
            sprintf(logStr, "foreCon = %d, ... exiting.", foreCon);        // LINE 'A' : THIS LINE ENDS UP IN OUTPUT FILE
            tCase->logEntry( string(logStr) );
            return false;
        } else {
            sprintf(logStr, "foreCon = %d, overwriting file.", foreCon);   // LINE 'B' : THIS LINE ENDS UP IN LOG FILE
            tCase->logEntry( string(logStr) );
        }                                                                                                 
    }

    // Initialize output file
    FILE *outFile;
    if( !initFile(outFile, dataFileName) ) {
        sprintf(logStr, "couldn't initFile '%s'", dataFileName.c_str());
        tCase->logEntry( string(logStr) );
        return false;
    }

    fprintf(outFile, "%s", data.c_str());                 // print data to output file

    if( fclose(outFile) != EOF) {
        sprintf(logStr, "saved to '%s'", dataFileName.c_str());
        tCase->logEntry( string(logStr) );
        return true;
    }

    return false;
}

ファイルが既に存在し、AND ' int foreCon= -1' の場合、コードは行 'A' を logFile に出力する必要があります。ファイルが存在し、foreCon!= -1 の場合、古いファイルは で上書きされdataます。ファイルが存在しない場合は作成され、データが書き込まれます。

ただし、結果として、行 'A' の分割バージョンがデータ ファイルに表示され、行 'B' がログ ファイルに出力されます!!!!

データ ファイルは次のようになります。

.. exiting.20130127 161456
20130127 000000,55,17,11,0.00
20130127 010000,54,17,11,0.00
... ...

2 行目以降は正しいように見えますが、「A」行の一部を含む余分な行があります。

さて、本当に奇妙な部分です。if( foreCon == -1) { ... }ブロック内のすべてをコメント アウトすると、データ ファイルは次のようになります。

%d, ... exiting.20130127 161456
20130127 000000,55,17,11,0.00
20130127 010000,54,17,11,0.00
... ...

まだ余分な行がありますが、それはデータ ファイルにコピーされた LITERAL CODE です。

私のコードにはポルターガイストがあると思います。どうやってこれが起こるのか理解できません。


編集:文字列をコンソールに印刷しようとしましdataたが、同じめちゃくちゃな値が返されます:%d, ... exiting.20130127 161456つまりstringFILE *

4

3 に答える 3

2

最新のコメントに基づく回答:

getDataPrefixStr() は、string retStr = COMCHAR + " file created on ..."; のようなもので始まる文字列を返すことになります。const char COMCHAR = '#'; など。COMCHARが問題になる可能性がありますか??

そのような文字や文字列リテラル (charではなくstringの配列) を追加することはできません。

" file created on ... " のアドレスに 35 ("#" の ASCII) を追加しています。すべてのリテラル文字列は同じデータ領域に一緒に格納されるため、出力でプログラムから文字列を取得します。

代わりに、あなたは冷たいです

   const string COMCHAR = "*"; 
   string retStr = COMCHAR + " file created on ...";
于 2013-01-27T22:00:38.493 に答える
1

logStr短すぎて、他のバッファでデータが上書きされている可能性があります(再確認しましたCHARLIMIT_LARGEか?)。logStrsprintf)へのすべての書き込みにコメントを付けることでこれを診断し、dataまだ破損していないかどうかを確認できます。dataFileName一般に、ユーザーが(非常に長い文字列になるように)設定できる場合、コードはこれに対して脆弱です。snprintfまたはのostringstream代わりに使用します。

そうでなければ、stu->getDataPrefixStr()またはgetDataFromURL()が破損した結果を返すか、char*の代わりにタイプを返すと推測しますstring。これらの値をコンソールに直接出力して、破損していないかどうかを確認してください。それらがを返す場合、char*未定義data = stu->getDataPrefixStr() + getDataFromURL()の動作になります。

于 2013-01-27T21:53:51.240 に答える
-1
if( temp = fopen(fname.c_str(), 'r') ) { 

する必要があります

if( temp = fopen(fname.c_str(), "r") ) { 
于 2013-01-27T21:07:43.510 に答える