0

私を悩ませているものがありますが、インターネットを介して答えを見つけることができません (または、少なくとも私はそれを検索する方法がわかりません)。行列のサイズを SIZE として宣言するとき、行列の最初の要素は 0 で、最後の要素は SIZE-1 であると常に考えていました。ただし、これをコンパイルすると:

#include<cstdio>
#include<cstdlib>
int main()
{
   double *r;
   r = new double[10];
   double dr=0.1;
   for(int i=0;i<=10;i++) r[i]=(double)i*dr;
   for(int i=0;i<=10;i++) printf("%lf\n",r[i]);
   delete [] r; r=0;
   return 0;
}

エラーは通知されず (これまでに gnu、dev、および c-free の 3 つのコンパイラでこれを試しました)、exe を実行してもエラーは発生しません。結果は次のとおりです。

0.000000
0.100000
0.200000
0.300000
0.400000
0.500000
0.600000
0.700000
0.800000
0.900000
1.000000---> element SIZE, which means 11, while I have declared 10 elements.

では、問題は次のとおりです。これはどのように可能ですか?!?!!? 住所を印刷したときの結果は次のとおりです。

006E0F88
006E0F90
006E0F98
006E0FA0
006E0FA8
006E0FB0
006E0FB8
006E0FC0
006E0FC8
006E0FD0
006E0FD8---> 11th element

前もって感謝します。

4

3 に答える 3

4

サイズの配列のインデックスがからまでのN範囲であることは正しいです。0N-1

境界を超えて配列にアクセスすることにより、未定義の動作を呼び出しています。これはコンパイル エラーではありませんが、そのようなコードを実行すると、予期しない結果が発生します。

于 2013-05-26T14:54:00.887 に答える
3

C および C++ では、「未定義の動作」の概念を理解することが非常に重要です。

これら 2 つの言語の主な前提は、プログラマーがエラーを犯さないことです。配列を超えて書き込むことはありません。オブジェクトを 2 回削除することも、符号付き整数を計算してオーバーフローさせることもありません。

これは、コンパイラと標準ライブラリによって生成されたコードがそのような可能性を無視できることを意味し、何が起こっても起こります。

悪いことをすると (つまり、OS 自体が意味のない操作をブロックするなど)、コードでセグメンテーション違反が発生する可能性がありますが、これは幸運な場合にのみ発生します。ほとんどの場合、何も起こりません。よく言えば、明らかなことは何も起こりません...しかし、100万回実行された命令の後で、完全に有効なコードが狂ったように動作する可能性があります。

C および C++ では、segfault をトリガーするコードが、ずっと前に発生した何らかのミスの罪のない犠牲者であることは非常に一般的です。

したがって、C および C++ でコーディングするときは、決して間違いを犯さないように注意してください ;-)

于 2013-05-26T15:01:33.490 に答える
0

0からへのループは、<=1011個の要素にアクセス/出力します。

これがUBです。配列の境界を越えてアクセスすることは UB です。

これでコードが修正されます。

#include<cstdio>
#include<cstdlib>
int main()
{
   double *r;
   r = new double[10];
   double dr=0.1;
   for(int i=0;i<10;i++) r[i]=(double)i*dr;
   for(int i=0;i<10;i++) printf("%lf\n",r[i]);
   delete [] r; r=0;
   return 0;
}

コードには構文エラーや未解決の参照がないため、コンパイラはプログラマを信頼し、この UB を通過させます。LINTツールはおそらくこの間違いをキャッチできますが、確かではありません。

于 2013-05-26T14:54:28.537 に答える