1

私はこの言語の初心者で、この問題に遭遇しました。ネットで検索した後、メモリ割り当て、ポインタなどに関連しているようです..私はよく理解していませんでした....ここでは、クラスを介してバイナリファイルにデータを追加しようとしています...何が問題なのか -->

void addques()
{
    question abc;
    ofstream fout;
    fout.open("question.txt",ios::app|ios::binary);
    cout<<"Enter Question!\n";
    gets(abc.ques);
    cout<<"Enter Options!\n";
    gets(abc.option1);gets(abc.option2);gets(abc.option3);gets(abc.option4);
    cout<<"Enter correct option number\n";
    cin>>abc.k;
    cout<<"Enter question nummber"; cin>>abc.quesno;
    fout.write((char*)&abc,sizeof(abc));
    fout.close();
    cout<<"File closed";
}

ifstream/ofstream クラス オブジェクトを持つすべての関数がこのエラーを表示しているようです。最後の行「File Closed」も実行され、その後エラーが表示されます。この行でしょうか -- fout.write((char*)&abc,sizeof(abc)); ??? 親切に助けて

これは関連するクラスです -->

class question
{   public:
    char ques[80];
    char option1[50], option2[50], option3[50], option4[50];
    char k;
    char quesno;
};

プログラム全体について、コードをここに貼り付けました http://pastebin.com/S7KNby0E 親切に見てください...ここではできなかったので

4

2 に答える 2

2

バッファの 1 つには長すぎる質問または回答を入力していませんか? クラスの境界を超えて、スタックを破壊しています。また、cin と cout と、gets のような C スタイルの IO 関数を混在させると問題が発生するため、使用しないでください。

C++ を使用しているため、文字配列として文字列操作を行う必要はありません。すべてのメモリがらくたを処理する STL クラスがあります。クラスを次のように書き直します。

class Question
{   public:
    string ques;
    string option1, option2, option3, option4;
    char k;
    char quesno;

    void write(fstream& f)
    {
        f << ques.length() << " " << ques << endl
          << option1.length() << " " << option1 << endl
          << option2.length() << " " << option2 << endl
          << option3.length() << " " << option3 << endl
          << option4.length() << " " << option4 << endl
          << k << " " << quesno << endl;
    }
};

そしてあなたの機能は次のようになります:

void addques()
{
    Question abc;
    ofstream fout;
    fout.open("question.txt", ios::app);

    cout << "Enter Question!" << endl;
    getline (cin, abc.ques);

    cout << "Enter Options!\n";
    getline(cin, abc.option1);
    getline(cin, abc.option2);
    getline(cin, abc.option3);
    getline(cin, abc.option4);

    cout << "Enter correct option number: ";
    cin >> abc.k;

    cout << "Enter question number: ";
    cin >> abc.quesno;

    // you will have to change your writing method a bit because you can't just write the string object straight to disk like you were before

    abc.write(fout);
    fout.close();
}

次に、抽出演算子を使用して、書き込みとほぼ同じ方法でストリームに読み込むことができるはずです。

アスキーからバイナリへ

バイナリを使用する必要があるため、次の方法で整数値をバイナリ値として格納できます。

int i = ques.length();
fout.write((const char *) &i, sizeof(i));

これにより、最初に文字列に変換せずに、32 ビット整数値がストリームに直接書き込まれます。文字列は次の形式になります。

+     0x0     0x1     0x2     0x3     0x4     0x5     0x6     0x7     
0x0  [0x00    0x00    0x00    0xC0  ][H       E       L       L
0x8   O       <space> W       O       R       L       D       <null> ]

長さは最初の 4 バイトで、ここでは 0x0000000C (整数値 12) として示されています。文字列はすぐ後に続き、値は "HELLO WORLD\0" です。\0 はヌル ターミネータです。私の例では、この長さには null ターミネータが含まれています。

のサイズ

Sizeof は、指定された型のメモリ内のサイズを、コンパイラが決定できる最適なサイズで生成する演算子です。int、short、char などの整数型の場合、その型で使用されるバイト数が返されます。配列の場合、紛らわしい動作に遭遇する可能性があります。静的に宣言された固定サイズの配列に対して呼び出された場合、sizeof は配列の長さ * 1 つの要素のサイズを返します。

int derp[1000];
sizeof(derp); // sizeof(int) * 1000

コンパイラが配列の大きさを認識していない場合、得られるのは最初の要素へのポインタのサイズです。ので注意してください。ポインターで sizeof を使用して配列サイズを決定することはできません。

int derp2[];
sizeof(derp2); // sizeof(int *), probably 4 or 8
int * derp3 = derp;
sizeof(derp3); // sizeof(int *), probably 4 or 8

std::string (STL 文字列クラス) の長さを取得するには、length メンバーを使用します。

string hurr = "hello world";
hurr.length(); // does NOT include the null terminator
               // length of string AND terminator is hurr.length() + 1
于 2012-08-03T18:54:15.627 に答える
1

明らかな問題があり、多くの潜在的な問題があります。あなたの症状は、値がメモリに書き込まれるべきではない場所(バッファオーバーラン、フローティングポインタなど)に書き込まれたことを示しています。

懸念

  1. C++標準ストリームI/O(std :: cout、std:cerr、std:cin、std :: ofstream、およびその他多くの要素)をCスタイルの標準I / O(gets)と混合しないでください。I / Oライブラリを1つ選択し、それを使い続けます。

  2. 境界条件に関する仮定を確認して確認します。この場合の境界は、の入力文字配列のサイズですquestion。入力データが配列サイズ(定義した制限)に近づいていますか/近づいていますか?各char配列の最後に余分な終了NULL(0)文字用のスペースを確保しましたか?

  3. 作業するすべてのものを事前に初期化します。questionニュートラルな「空のデータ」が新しいものに存在することを保証するために、コンストラクターは何ができますquestionか?

戦略-問題を切り分ける

  1. 関数を空のままにして、関数本体全体(すべてのステートメント)をコメントアウトします。実行して、それが機能するかどうかを確認します-これにより、問題が身体にあるのか、それとも他の場所にあるのかが特定されます。

  2. ビットを追加し直します。どのステートメントが問題を引き起こしたかを正確に特定します。アクセス違反では、このタイプのコードトリアージが真の原因を明らかにしない可能性があるという懸念があります。

例外:バッファオーバーラン、フローティングポインタなどは、問題が発生した後、いつでもどこでも問題を引き起こす可能性があります。世界のすべての問題の切り分けは、問題の原因を特定できない場合があります。一般的な問題を認識するスキルを身に付けます。上記のポイントは、これらのスキルの開発に役立ついくつかの開始ガイドラインとなることを目的としています。

スタイル

  1. 各変数を、コードで最初に使用するポイントのできるだけ近くで宣言します。宣言をfout下に移動することを検討してください。
于 2012-08-03T18:36:44.237 に答える