1

私は現在C_String、文字列へのポインタを使用して変更するプログラムを書いています。私は正常に動作する実装を持っています。私が直面している唯一の問題は、プログラムの最後に到達したときに、ポインターを削除しようとするとエラーが発生することです。

私のコード:

void CStringSwitcher()
{

    string input = "";
    char* cStringArray = new char[ASIZE];
    char* reversed = new char[ASIZE];
    const char* originalReversed = reversed;
    char* pointers[POINTER_SIZE];
    memset(reversed, '\0', ASIZE);
    memset(cStringArray, '\0', ASIZE);
    memset(pointers, '\0', POINTER_SIZE);
    char* current = cStringArray;
    cout << "Enter a sentence on each line. Input a 0 to stop." << endl;

    // Receives input from the user and stores it into cStringArray
    int i = 0;
    do
    {
        cout << ">";
        cin.clear();
        fflush(stdin);
        input = "";
        getline(cin, input);
        if (input == "0")
            break;
        else
        {
            input.append("\n");
            pointers[i] = current;
            _CRT_SECURE_STRCPY(pointers[i], ASIZE - 1, input.c_str());
            current += input.length();
            i++;
        }
    } while(i < POINTER_SIZE);
    char* end = current;

    --i;
    do
    {
        /// Check if done
        if(i < 0)
            break;
        /// Copy from current to end
        current = pointers[i];
        do
        {

            *reversed++ = *current++;
        }while(current < end);
        /// Update end
        end = pointers[i];
        /// Update i
        --i;
    }while(true);
    *reversed = '\0';
    cout << endl << originalReversed << endl;
    system("PAUSE");
    //delete[] originalReversed;
    //delete[] cStringArray;
    return;
}

上に書かれているように、コードは正常に動作しますが、リターンの直前にある 2 つの削除行のコメントを外すと、エラーが発生しました。

Project_06.exe がブレークポイントを開始しました

そしてプログラムがクラッシュします。奇妙なことに、エラーメッセージの正確な文言を取得するためにプログラムを再度実行したところ、エラーなしで実行されましたか? それがなぜなのかについてのアイデアはありますか?

4

2 に答える 2

1

このコードは、ポインターに関する知識を固めるための教育/実践的なものだと思いますが、率直に言って、読むのは絶対に恐ろしいことです。

この答えは、「人に釣りを教える」という精神に基づいています。

すべての割り当てを削除することから始め、代わりに固定サイズの配列を使用します。

char cStringArray[ASIZE] = "";
char reversed[ASIZE] = "";

これにより、現時点では memset の必要がなくなります。この割り当てにより、実際には配列全体が 0 に設定されます ( http://ideone.com/WmLtQpを参照)。

このようにすると、デバッガーを使用して実行中に破損を検出するのがはるかに簡単になります。

次に、配列を動的割り当てに切り替えます。

最後に、stdin と cin を混在させないでください。混在させると、未定義の動作が発生する可能性があります。

- - 編集 - -

これは、コードの C++ リファクタリングです。この特定の部分では、手動で行う方法 (手動でバイトをコピーする方法) と、C++ 機能を使用して自分で行う必要がある作業の量を減らす方法の両方を示します。

ideone ライブ デモ: http://ideone.com/0KuGiB

#include <iostream>
#include <string>
#include <vector>

void CStringSwitcher()
{
    std::vector<std::string> inputs;
    size_t totalLength = 0;

    std::cout << "Enter a sentence on each line. Input a 0 to stop." << std::endl;
    inputs.reserve(16);

    for ( ; /* until break */ ; ) {
        std::cout << ">";
        std::string input;
        getline(std::cin, input);
        if (input == "0")
            break;
        inputs.push_back(input);
        totalLength += input.length() + 1; // for the '\n'
    }

    std::string reversed = "";
    reversed.reserve(totalLength); // eliminate allocations

    // walk backwards thru the list of strings.
    for (auto inputsIt = inputs.rbegin(); inputsIt != inputs.rend(); ++inputsIt) {
        const std::string& input = *(inputsIt);

#ifndef REAL_CODE
        // educational, Do-It-Yourself way
        const size_t length = input.length();

        // walk backwards thru the characters
        for (size_t i = 0; i < length; ++i) {
            reversed += input[length - 1 - i];
        }
#else
        // call append with reversed iterators to do it for us.
        reversed.append(input.rbegin(), input.rend());
#endif

        // add the trailing '\n'
        reversed += '\n';
    }

    std::cout << std::endl << reversed << std::endl;

    // don't pause, set a break point at the end of the function
    // or run without debugging.

    return;
}

int main(int argc, const char* argv[])
{
    CStringSwitcher();

    return 0;
}
于 2013-11-10T18:32:22.327 に答える
0
_CRT_SECURE_STRCPY(pointers[i], ASIZE - 1, input.c_str());
current += input.length();

ASIZE-=input.length();

ASIZE-=input.length();

エラーを取り除くのに役立つ理由がわかりません。これは、新しい文字列のサイズ > 残りのバイトのサイズの場合にのみ、オーバーフローを防ぎます。マイクロソフト固有の魔法のように見えます。

また、コードには多くのエラーがありますが、これは別の話です。vector、unique_ptr の使用を検討してください。

- -編集 - -

変なものを持ってきました。

_CRT_SECURE_STRCPY は strcpy_s に定義されています

#include <iostream>
#include <numeric>

using namespace std;

int main()
{
    char arr[10];
    iota(arr, end(arr), 'A');
    for (auto i : arr) cout << i << '\t'; cout << '\n';

    strcpy_s(arr, "");

    for (auto i : arr) cout << i << '\t'; cout << '\n';
}

私の出力は次のとおりです。

ABCDEFGHIJ

(非優先文字)

これは、strcpy_s が宛先バッファー全体を書き換えることを意味します。1文字渡しても。

于 2013-11-10T19:18:35.483 に答える