5

これが初心者の質問である場合は申し訳ありません:(。

Cコードの一部。

int array[5];
int cnt;

for(cnt = 0; cnt <= 10; cnt+=1)
{
      array[cnt] = cnt;
}

エラーを出す必要がありますよね?いいえ!正常に動作します!しかし、それはなぜですか?-最初の行で-doubleサイズ(11)を超える配列が定義されているようです。後でarray[5から10]にアクセスすることもできます。そして、それは私を混乱させています。array[4以下]を定義すると動作を停止します...

前もって感謝します。

4

9 に答える 9

24

特定のコンパイラやコンピュータで動作する可能性がありますが、それを当てにするべきではありません。

C言語仕様に従ったコードの動作は未定義です。これは、それがあなたが望むことをするかもしれない、あるいはそれがあなたのコンピュータをクラッシュさせるかもしれない、あるいはそれがあなたの鼻から悪魔を飛ばすかもしれないことを意味します。

JavaやC#などの高級言語とは異なり、Cはユーザーを信頼し、配列の境界に対して明示的なチェックを実行しません。あなたは責任を負い、アレイの境界の外を踏み出さないことになっています。

于 2009-04-27T20:40:21.163 に答える
17

これは、「動作」の定義が「まだクラッシュしていない」と同義である場合にのみ「動作」します。

于 2009-04-27T20:42:59.253 に答える
5

表示されているのは、無効なインデックスを使用して配列にアクセスしたために発生した未定義の動作です。未定義の動作とは、プログラムが正しく機能しているように見えることを含め、何かが起こる可能性があることを意味します。

于 2009-04-27T20:43:25.570 に答える
4

「でも、それはなぜですか?」

それがCのやり方だからです。

配列の境界は実行時にチェックされません。

それが「Cの法則」です

于 2009-04-27T20:40:32.253 に答える
4

これはすべて実際には定義されていないことを指摘したいだけです。この特定の例では、両方の変数がスタック上にあるため、この例は「機能」します。つまり、cnt のアドレスは配列の末尾のすぐ下にあります。cnt が cnt==5 に達すると、ステートメント array[cnt]=cnt; 配列専用のメモリには書き込みませんが、cnt のアドレスが配置されているその直後に書き込みます。それがあなたのカウンターを変えないのはただの運です。cnt>5 の場合、破棄するメモリがなく、「スタック void」に書き込むだけです (適切な単語がわからない)。

これを説明する別の例:

int main(int ac,char **av)
{
    int a[5];
    int cnt;
    int cnt2=3;

    for(cnt=0;cnt<7;cnt++) {
        a[cnt]=cnt;
        printf("%d %d %d\n", a[cnt], cnt, cnt2);
    }
}

出力:

0 0 3
1 1 3
2 2 3
3 3 3
4 4 3
5 5 5
6 6 5

ループの最後の 2 つの書き込みは、a[] の後のスタック データを上書きし、非常に紛らわしいエラーが発生する可能性があります。この場合、cnt2 は破棄されます。

于 2009-04-28T15:57:10.523 に答える
2

C の配列は実行時にチェックされません。言い換えれば、サイズ N の配列を「定義」し、バインドされた配列の末尾から喜んでアクセスできます。配列の最後から外れると、スタック (またはヒープ) のどこかでメモリが破棄されます。

メモリをどこかに捨てると、プログラムがクラッシュする可能性があります。これらのクラッシュは、アレイの最後を実際にオーバーランした場所から遠く離れた場所でクラッシュする可能性があるため、追跡するのが難しい場合があります。

通常、C で配列を宣言するときは、ある種の定数または #define を使用して配列のサイズをマークすることをお勧めします。

#define MAX_ELEMENTS 10
int array[MAX_ELEMENTS];
int cnt;
for(cnt = 0; cnt < MAX_ELEMENTS; cnt+=1) {
   array[cnt] = cnt;
}

配列の代入で MAX_ELEMENTS を超えると、cnt の値を上書きする可能性があります。他の変数を上書きする可能性があります。すべてはコンパイラとコード構造に依存します。また、for ループでの < 記号の使用にも注意してください。C 配列は 0 ベースであるため、less-than を使用してチェックし、less-than-or-equal-to をチェックする必要はありません。

于 2009-04-27T20:47:47.183 に答える
1

C の配列境界は、実行時に必ずしもチェックされるとは限りません。標準では、実装者が選択するかどうかにかかわらず、自由に実行できます。これはundefinedの一部です。ファット ポインターを使用した実装では、サンプルによって実際に何らかのエラーが発生する可能性があります。

于 2009-05-01T03:37:04.413 に答える
0

配列の最後から実行すると、ソフトウェアが予期していないメモリを上書きし、ヒープを破壊します。ソフトウェアは引き続き実行される可能性がありますが、非常に不安定になります。

于 2009-04-27T20:43:11.203 に答える
0

スタックメモリのパック方法によって異なります。また、それらの値を喜んで上書きし、読み取ることもできますが、スタックが破損している可能性があります。

于 2009-04-27T20:43:19.020 に答える