これは典型的なポインタ嫌いの質問ではなく、むしろ非常に興味深い質問です。
ポインターは非常に強力な概念ですが、それは概念です。では、なぜ C コンパイラは、ポインタ専用のこのように独立したロジックと構文を備えて発明されたのでしょうか?
誤解しないでください。私はポインターが提供する機会とその現在の構文が大好きです。これらは、動的データ構造、オブジェクトとクラス、マルチスレッドのメモリ共有、オブジェクトの変更可能性、低冗長性の値の重複などの進化を実現した、絶対に不可欠な機能です。
しかし、C 言語の発明の出来事を想像してみると、今日のポインタは直感的な最初の概念よりもはるかに印象的なアイデアに見えます。私が言いたいことをもっと深く見てみましょう。
ポインタの構造を見ると、基本的に unsigned long (別名 4[32 ビット システム]、またはメモリ内の 8 バイト) です。ポインターを unsigned long から区別するものは、ポインター固有の機能です。
ポインターには独自の宣言構文があり、そのプロパティ演算子である逆参照子があります。
int a = 5; int *ptr = &a; //declaration int value = *ptr; //dereference
しかし、これが決して発明されたものではないと想像してみましょう。逆参照機能が任意の整数型に関連付けられている場合、次のことが簡単に可能になります。
int a = 5; unsigned long adress = &a; int value = *adress;
その場合、次のようなこともできます:
int firstIntInMemory = *(0); //manually dereferences (4bytes at) adress 0`
パーサーについて言えば、参照解除子としての star は単項演算子であるのに対し、算術乗算子としての star は常に 2 項演算子であるため、これはまったく矛盾する構文ではありません。
上で説明したこの架空の逆参照演算子は、実際にはポインターの概念の生の本質です。これを現在の実際の実装と比較すると、頭の疑問は考えるのが非常に興味深いものになります。非常に多くの結果があった可能性があります。
ポインター演算で行う唯一の特別なことは、計算に型のサイズを考慮することです。配列があり、2 番目の要素を取得したい場合は、ポインタに 1 を追加するだけです。それが int ポインターの場合、実際には暗黙的に 4 の値がアドレスに追加されます (システム上で sizeof(int) == 4 の場合):
int arr[5] = {1,2,3,4,5}; int second = *(arr + 1);
しかし、正直に言うと、メモリについて直感的に考えると、実際には次の方がはるかに論理的です。
int arr[5] = {1,2,3,4,5}; int second = *(arr + sizeof(int));
これは単なる標準的な整数演算です。このように考えると、ポインター演算を発明した理由はまったくありません。
もちろん、「*」構文を使用すると、使用目的がより明確になります。これを見れば、この変数がメモリ操作に使用されていることがすぐにわかります。また、すべてのメモリ操作ライブラリ関数はポインター用に設計されています。
それでも、もしそれが発明されず、代わりにこれらの間接参照可能な unsigned long があったとしたら、人々は単にポインタ変数識別子に '_p' 接尾辞を追加するなどの設計規則と命名規則を思いついたでしょう。そして、メモリ操作ライブラリはこれを中心に進化したでしょう。
つまり、よく考えてみると、ポインタが言語の機能として発明されていなければ、C は現在と同じように生き残っていたかもしれません。これらはプログラマーによって概念として発明されるだけで、現在存在するものと同じように機能します。
これは、さらに深く調査するのに興味深い話だと思います。
なぜ C はポインタを発明したのですか?
それは単に私たちが期待していた理由、つまり一貫性、明確さ、参照解除の誤用に対する安全性だったのでしょうか?
それとも、この投稿でポインターについて説明したよりも、より深い理由と、より複雑なロジックがあり、それにより、汎用の整数で同じことを行うよりも実際にポインターの効率が大幅に向上するのでしょうか?
以上が暗黙の質問:「なぜポインターが存在するのですか?」の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。