12


3

私はKを読んでいます Cはメモリに関してほとんど何でもできることを知っていますが、私は理解していません。この特殊性の目的は何ですか?

3 Answer


19


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

したがって、これは問題ありません。

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

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

(「+ * end +」を実行するとエラーになります。)

それが、この機能が便利な理由を示しています。配列の末尾の後に(存在しない)要素を指すポインタが、ループ内などの比較に役立ちます。

技術的に言えば、それがC標準で認められているすべてです。 ただし、実際には、Cの実装(コンパイラおよびランタイム)では、配列の末尾を超えてメモリにアクセスするかどうか、つまり1つ以上の要素であるかどうかはチェックされません。 境界チェックが必要になり、プログラムの実行が遅くなります。 Cが最も適している種類のプログラム(システムプログラミング、汎用ライブラリ)は、セキュリティおよび安全性の境界チェックよりも速度の面で有利です。

つまり、Cはおそらく汎用アプリケーションプログラミングには適していないということです。


16


多くの場合、実際の割り当ての1つ前の「終了」位置を示すと便利なので、次のようなコードを書くことができます。

char * end =開始サイズ。 for(char * curr = begin; curr </ *または!= * / end; curr){/ *ループ内で何かをする* /}

C標準では、この要素は有効なメモリアドレスであると明示的に述べられていますが、それを間接参照することはまだお勧めできません。

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

16バイト連続して空いていますが、

開始サイズ== FFF0 10(16進数で16)== 10000

これは、ポインタサイズのために0000に折り返されます。 今ループ条件:

curr <end == FFF0 <0000 == false

配列を反復処理する代わりに、ループは何もしません。 これは多くのコードを壊すでしょう、それでC標準は割り当てが許されないと言います。


-1


あなたは例えば配列を過ぎて1をはるかに超えて行くことができます

int main(){char * string = "string"; int i = 0。 (i = 0; i <10; i){printf( "%c \ n"、string [i]); 0を返します。 }

文字列の末尾の後にゴミを表示します。