2009-06-20 6 views
11

私はCの本のK &を読んでいて、Cのポインタ算術は配列の終わりを越えて1つの要素にアクセスできることを発見しました。私はCが記憶でほとんど何でもできることを知っているが、私は理解していない、この特異性の目的は何ですか?C - 配列の終わりを超えた要素

+1

この質問もご覧ください:http://stackoverflow.com/questions/988158/take-the-address-of-a-one-past-the-end-array-element-via-subscript-legal-by- –

答えて

19

Cは、アレイの終わりを超えてメモリにのアクセスアクセスを許可しません。ただし、ポインタが配列の終わりを超えて1つの要素を指すことができます。この区別は重要です。

したがって、これはOKです:

char array[N]; 
char *p; 
char *end; 

for (p = array, end = array + N; p < end; ++p) 
    do_something(p); 

*endを行うと、エラーになります。)

そして、それはこの機能が便利である理由を示しています(存在しないで指し示すポインタを)要素は、inループなどの比較に役立ちます。

技術的に言えば、それはC標準が許すすべてのものです。しかし、実際には、Cの実装(コンパイラとランタイム)では、配列の最後を超えてメモリにアクセスするかどうかは、要素が1つ以上であるかどうかをチェックしません。境界チェックが必要になり、プログラムの実行が遅くなります。 Cプログラムの種類(システムプログラミング、汎用ライブラリ)は、セキュリティと安全境界チェックよりもスピードが向上する傾向があります。

つまり、Cは多分汎用アプリケーションプログラミングのための良いツールではありません。

15

は多くの場合、あなたのようなコードを書くことができますので、実際の配分過去1である「終了」の位置を示すために役立ちます。

char * end = begin + size; 
for (char * curr = begin; curr < /* or != */ end ; ++curr) { 
    /* do something in the loop */ 
} 

C標準は、明示的にこの要素が有効であることを述べていますメモリアドレスが、逆参照はそれでも良い考えではありません。

なぜこの保証がありますか?たとえば、2^16バイトのメモリを持ち、アドレス0000-FFFF、16ビットのポインタを持つマシンがあるとします。 16バイトの配列を作成したとします。 FFF0でメモリを割り当てることができますか?

あり16のバイトが連続して無料ですが、:

begin + size == FFF0 + 10 (16 in hex) == 10000 

ため、ポインタのサイズを0000にラップしています。ここでループ条件:

curr < end == FFF0 < 0000 == false 

ループの代わりに何もしません。これは多くのコードを破るので、Cの標準では割り当ては許されないと述べています。

-1

あなたが手の前にメモリ内に座っていたどんな単語列の末尾の後にゴミを出力しますexample`

int main() 
{ 
     char *string = "string"; 
     int i = 0; 
     for(i=0; i< 10;i++) 
     { 
       printf("%c\n", string[i]); 
     } 
     return 0; 
} 

のために、アレイ を過ぎても1を超えて行くことができます。

+6

ゴミを印刷したり、ハードドライブをフォーマットしたり、悪魔を鼻から飛ばしたりするかもしれません。そのようなものは未定義の振る舞いの性質です。 – aib

+0

さて、メモリの場所から読んだだけでは、あなたのハードドライブをフォーマットしたり、悪魔を鼻から飛ばすことはありません。しかし、それに書き込む... –

+3

悪いポインタを読んでも、将来あなたのプログラムがクラッシュする可能性があります。 http://blogs.msdn.com/oldnewthing/archive/2006/09/27/773741.aspx – Eclipse

関連する問題