...割り当てられた範囲外のポインタを単にデクリメントすることは、私にとって非常に大ざっぱなようです。これはCの「許可された」動作ですか?
許可された?はい。良いアイデア?普通ではありません。
Cはアセンブリ言語の省略形であり、アセンブリ言語にはポインタはなく、メモリアドレスのみがあります。Cのポインターは、算術を受けたときにポイントするサイズによって増加または減少するという副次的な動作を持つメモリアドレスです。これにより、構文の観点から次のことがうまくなります。
double *p = (double *)0xdeadbeef;
--p; // p == 0xdeadbee7, assuming sizeof(double) == 8.
double d = p[0];
配列は、実際にはCのものではありません。それらは、配列のように動作する連続したメモリ範囲への単なるポインタです。[]
オペレータはそう、ポインタ演算を行うと、逆参照の省略形ですa[x]
実際の手段*(a + x)
。
上記を実行する正当な理由があります。たとえば、いくつかのI / Oデバイスがとにdouble
マップされます。それを行う必要のあるプログラムはほとんどありません。0xdeadbee7
0xdeadbeef
&
演算子の使用やの呼び出しなどによって何かのアドレスを作成する場合malloc()
、元のポインターをそのままにしておき、そのポインターが実際に有効なものであることがわかるようにします。ポインターのデクリメントは、誤ったコードの一部がそれを逆参照しようとし、誤った結果を得たり、何かを破壊したり、環境によってはセグメンテーション違反を犯したりすることを意味します。これは、で特に当てはまりmalloc()
ます。なぜならfree()
、元の値を渡すことを覚えている人に負担をかけているのであり、変更されたバージョンではなく、すべての問題が解消されるからです。
Cで1ベースの配列が必要な場合は、使用されない追加要素を1つ割り当てることを犠牲にして安全に行うことができます。
double *array_create(size_t size) {
// Wasting one element, so don't allow it to be full-sized
assert(size < SIZE_MAX);
return malloc((size+1) * sizeof(double));
}
inline double array_index(double *array, size_t index) {
assert(array != NULL);
assert(index >= 1); // This is a 1-based array
return array[index];
}
これは上限を超えないように保護するものではないことに注意してください。ただし、これは簡単に処理できます。
補遺:
C99ドラフトのいくつかの章と詩(申し訳ありませんが、リンクできるのはそれだけです):
§6.5.2.1.1は、添字演算子で使用される2番目の(「その他」)式は整数型であると述べています。 -1
は整数であり、これによりp[-1]
有効になり、したがってポインターも有効になり&(p[-1])
ます。これは、その場所でメモリにアクセスすると定義された動作が生成されることを意味しませんが、ポインターは依然として有効なポインターです。
§6.5.2.2従って、ポインタに要素番号を追加の相当する配列添字演算子評価することを言うp[-1]
と等価です*(p + (-1))
。まだ有効ですが、望ましい動作が得られない場合があります。
§6.5.6.8によると(強調鉱山):
整数型の式がポインターに追加またはポインターから減算されると、結果はポインターオペランドの型になります。
...式が配列オブジェクトの-th要素をP
指す場合、式(同等に)および
(where の値は)は、存在する場合、それぞれ配列オブジェクトの-thおよび
-th要素を指します。i
(P)+N
N+(P)
(P)-N
N
n
i+n
i−n
これは、ポインター演算の結果が配列内の要素を指している必要があることを意味します。算術演算を一度に行う必要があるとは言いません。したがって:
double a[20];
// This points to element 9 of a; behavior is defined.
double d = a[-1 + 10];
double *p = a - 1; // This is just a pointer. No dereferencing.
double e = p[0]; // Does not point at any element of a; behavior is undefined.
double f = p[1]; // Points at element 0 of a; behavior is defined.
このようにすることをお勧めしますか?私はしません、そして私の答えはその理由を説明します。