1

注:私はC++コンパイラを使用しているため、参照渡しを使用できる理由

奇妙な問題があり、何が起こっているのかよくわかりません。

基本的に、テキスト ファイルがあります: http://pastebin.com/mCp6K3HB で、テキスト ファイルの内容をアトムの配列に読み込んでいます。

typedef struct{
    char * name;
    char * symbol;
    int atomic_number;
    double atomic_weight;
    int electrons;
    int neutrons;
    int protons;
} atom;

これは私のアトムの型定義です。

void set_up_temp(atom (&element_record)[DIM1])
{
    char temp_array[826][20];
    char temp2[128][20];
    int i=0;
    int j=0;
    int ctr=0;

    FILE *f=fopen("atoms.txt","r");

    for (i = 0; f && !feof(f) && i < 827; i++ ) 
    {
        fgets(temp_array[i],sizeof(temp_array[0]),f);
    }

    for (j = 0; j < 128; j++)
    {
        element_record[j].name = temp_array[ctr];
        element_record[j].symbol = temp_array[ctr+1];
        element_record[j].atomic_number = atol(temp_array[ctr+2]);
        element_record[j].atomic_weight = atol(temp_array[ctr+3]);
        element_record[j].electrons = atol(temp_array[ctr+4]);
        element_record[j].neutrons = atol(temp_array[ctr+5]);
        element_record[j].protons = atol(temp_array[ctr+6]);
        ctr = ctr + 7;
    }

    //Close the file to free up memory and prevent leaks
    fclose(f);
} //AT THIS POINT THE DATA IS FINE

これが、データを読み取るために使用している関数です。この関数をデバッグし、最後まで実行すると、デバッガーを使用してその内容を確認します。配列には 100% 正しいデータが含まれています。つまり、すべての要素がテキスト ファイルに対して相対的であるべきです。 http://i.imgur.com/SEq9w7Q.pngこの画像は、私が話していることを示しています。左側では、0 から 127 までのすべての要素が完全です。次に、呼び出し元の関数に移動します。

atom myAtoms[118];
set_up_temp(myAtoms); //AT THIS POINT DATA IS FINE
region current_button_pressed; // NOW IT'S BROKEN
load_font_named("arial", "cour.ttf", 20); 
panel p1 = load_panel("atomicpanel.txt");   
panel p2 = load_panel("NumberPanel.txt");

ANYTHING が呼び出されるとすぐに、 を呼び出した後set_up_temp、配列の要素 103 から 127 がぎこちなくなります。より多くのものが呼び出されると、さらに多くの配列がぎこちなくなります。これは奇妙です。何が起こっているのかわかりません。ありがとう。

4

3 に答える 3

7
for (j = 0; j < 128; j++)
{
    element_record[j].name = temp_array[ctr];

temp_arrayスタック上にあるにポインタを格納してから返します。関数から戻った瞬間、すべてが無効にtemp_arrayなります。その時点以降、これらのポインターのいずれかを逆参照するのは未定義の動作です。「未定義の動作」には、問題なく要素0から102を読み取ることができる可能性が含まれますが、あなたが言うように、103から127は意味不明になります。オブジェクトと同じくらい存続するこれらの文字列にスペースを割り当てる必要がありatomます。あなたがC++を使用していると言うので、最も簡単な修正は両方char *のメンバーをstd::string. ( を使用したくない場合std::string、2 番目に簡単な修正方法は を使用するstrdupことですが、その場合はfree明示的にそのメモリを使用する必要があります。)

これは、このコードの唯一のバグではないかもしれませんが、おそらく、差し迫った問題を引き起こしているものです。

興味がある方のために説明すると、データのハイエンドが破損している理由は、使用しているコンピューターを含むほとんどの (ただしすべてではない) コンピューターで、スタックが下向きに、つまり上位アドレスから下位に成長するためです。ただし、配列は常に下位アドレスから上位アドレスにインデックス付けされます。そのため、以前のメモリ領域temp_arrayの上限は、呼び出し元のスタック ポインターに最も近い部分であるため、後続の関数呼び出しによって上書きされる可能性が最も高くなります。

于 2013-04-25T17:35:59.900 に答える
3

さりげなく調べると、次のようになります。

char temp_array[826][20];

...

for (i = 0; f && !feof(f) && i < 827; i++ )

あなたのコードは潜在的iに になることを許可し826ます。これは、 の 827 番目の要素にアクセスしていることを意味しますtemp_array。これは終わりを過ぎたものです。おっとっと。

さらに、118 個のアトム ( ) の配列を割り当てていますが、ループatom myAtoms[118];内で 128 個を設定しています。set_up_tempfor (j = 0; j < 128; j++)

この話の教訓: インデックスに注意してください。C++ を使用std::vectorstd::stringているため、配列を直接操作することは避けてください。

更新 ザックが指摘したように、set_up_temp関数が戻ると消えるスタック割り当て変数へのポインターを返しています。さらに、fgetsあなたが使っている はあなたが思っていることをしませんし、そもそも恐ろしいコードです。のドキュメントを読んで、fgets自分のコードが何をするのか自問してください。

于 2013-04-25T17:33:49.680 に答える
2

118 個の要素用のスペースを持つ配列を割り当てていますが、コードはそれらの 128 個を設定しているため、配列の直後に発生したものはすべて上書きされます。

また、他の人が指摘したように、関数にとって一時的なデータへのポインターを配列に格納しています(ノーノー)。

私の提案は、プログラミングの前に C++ に関する優れた本を読むことから始めることです。C++ は、実験によって大きな進歩を期待できる言語ではありません。

于 2013-04-25T17:34:59.383 に答える