1

Code ::Blocks10.05とGNUGCCコンパイラを使用しています。

基本的に、宣言されたサイズの外側で配列を初期化しようとしたときに発生する、非常に奇妙な(そして私にとっては説明のつかない)問題に遭遇しました。言い換えれば、それはこれです:

*サイズ[x][y]の宣言された配列があります。

*サイズ[y-1]の別の宣言された配列があります。

この問題は、サイズsize [y-1]外のこの2番目の配列に値を入れようとすると発生します。[y-1]これを試みると、最初の配列[x][y]はそのすべての値を維持しなくなります。一方の配列を壊す(または壊そうとする)ことが他の配列の内容に影響を与える理由を私は単に理解していません。これが起こっていることを確認するためのサンプルコードです(壊れた形式です。問題が消えるのを確認するには、に変更array2[4]してくださいarray2[5](したがって、問題であると特定したものを削除します)。

#include <stdio.h>

int main(void)
{
    //Declare the array/indices
    char array[10][5];
    int array2[4]; //to see it work (and verify the issue), change 4 to 5
    int i, j;

    //Set up use of an input text file to fill the array
    FILE *ifp;
        ifp = fopen("input.txt", "r");

    //Fill the array
    for (i = 0; i <= 9; i++)
    {
        for (j = 0; j <= 5; j++)
        {
            fscanf(ifp, "%c", &array[i][j]);
            //printf("[%d][%d] = %c\n", i, j, array[i][j]);
        }
    }

    for (j = 4; j >= 0; j--)
    {
        for (i = 0; i <= 9; i++)
        {
            printf("[%d][%d] = %c\n", i, j, array[i][j]);
        }
        //PROBLEM LINE*************
        array2[j] = 5;

    }

    fclose(ifp);
    return 0;

}

それで、これがどのように、またはなぜ起こるのか誰かが知っていますか?

4

4 に答える 4

4

配列の境界の外側に書き込む場合、Cを使用すると可能になるためです。プログラムのどこかに書き込みをしているだけです。

Cは、最低レベルの高水準言語として知られています。「低レベル」の意味を理解するには、作成したこれらの変数のそれぞれが、物理的な記憶にあると考えることができることを覚えておいてください。長さ16の整数の配列は、整数のサイズが4の場合、64バイトを占める可能性があります。おそらく100〜163バイトを占める可能性があります(可能性は低いですが、現実的な数値を作成するつもりはありません。通常、これらは16進数で考える方が適切です)。バイト164を占めるものは何ですか?たぶんあなたのプログラムの別の変数。16個の整数の配列を過ぎたものに書き込むとどうなりますか?まあ、それはそのバイトに書き込むかもしれません。

Cではこれを行うことができます。なんで?答えが思いつかない場合は、言語を切り替える必要があります。私は衒学者ではありません-これがあなたに利益をもたらさないのなら、あなたはあなたがこのような奇妙な間違いをするのが少し難しい言語でプログラムしたいかもしれません。しかし、理由は次のとおりです。

  • それはより速くそしてより小さくなります。境界チェックの追加には時間とスペースがかかるため、マイクロプロセッサ用のコードを記述している場合、またはJITコンパイラを記述している場合は、速度とサイズが非常に重要になります。
  • マシンアーキテクチャを理解してハードウェアを使いたい場合、たとえば学生の場合は、プログラミングからOS/ハードウェア/電気工学への優れたゲートウェイです。そして、コンピュータサイエンスの多く。
  • 機械語に近いため、他の多くの言語やシステムがある程度の互換性をサポートする必要がある、または簡単にサポートできるという点で標準です。
  • 私が実際にこれをマシンコードの近くで作業しなければならなかった場合に私が与えることができる他の理由。

道徳は次のとおりです。Cでは、非常に注意してください。独自の配列境界を確認する必要があります。あなたはあなた自身の記憶をきれいにしなければなりません。そうしないと、プログラムがクラッシュしないことがよくありますが、場所や理由を教えずに、本当に奇妙なことを始めます。

于 2012-06-22T03:44:47.693 に答える
2
  for (j = 0; j <= 5; j++) 

する必要があります

  for (j = 0; j <= 4; j++)

そしてarray2最大インデックスは3そうです

  array2[j] = 5;

の場合も問題になりj == 4ます。

C配列インデックスは。から始まります0。したがって、[X]配列の有効なインデックスはfromから0までX-1であり、合計でX個の要素を取得します。

配列宣言と式の両方で同じ数値を表示する<には、の代わりに演算子を使用する必要があります。例えば<=[X]< X

  int array[10];
  ...
  for (i=0 ; i < 10 ; ++i) ... // instead of `<= 9`

これにより、エラーが発生しにくくなります。

于 2012-06-22T03:44:44.057 に答える
1

array2[j] = 5;- これはオーバーフローの問題です。

for (j = 0; j <= 5; j++)・これもオーバーフローの問題です。ここでも、0 番目から 4 番目のインデックスにしかアクセスできない 5 番目のインデックスにアクセスしようとしています。

プロセス メモリでは、各関数を呼び出すときに、関数のすべてのローカル変数を保持するために 1 つのアクティベーション レコードが作成されます。また、呼び出された関数のアドレスの場所を格納するためのメモリも追加されます。array関数には、 、array2iおよびの 4 つのローカル変数がありますj。この4つが順番に並びます。したがって、オーバーフローが発生した場合、最初にアーキテクチャに依存する上または下で宣言された変数を上書きしようとします。それ以上のバイトでオーバーフローが発生すると、呼び出された関数のローカル変数の一部が上書きされ、スタック全体が破損する可能性があります。これもクラッシュにつながるかもしれません。

于 2012-06-22T05:44:26.807 に答える
1

1 つの配列の境界外にいる場合、他の配列の境界内にいる可能性が常にあります。

于 2012-06-22T03:48:50.277 に答える