web-dev-qa-db-ja.com

若い心はポインターの概念を学ぶ必要がありますか?

Cマスター Dennis Ritchie がCにポインタを導入したのはなぜですか?そして、なぜVB.NETやJavaまたはC#のような他のプログラミング言語がそれらを排除したのですか?私はGoogleでいくつかのポイントを見つけました、そして私はあなたのコメントも聞きたいのです。なぜそれらはポインターの概念を排除したのですか?現代の言語で?

Cが基本言語であり、ポインターがCを強力で優れたものにし、Cがより現代的な言語と競争できるようにする概念であると人々は言います。では、なぜ彼らはより現代的な言語でポインタを排除したのでしょうか?

新しいプログラマにとって、ポインタの知識は依然として重要だと思いますか?人々はVB.NETまたはJavaを最近使用しています。これはCよりも高度な機能をサポートしており(ポインタの概念を使用していません)、私が今見ている多くの人々(私の友人)がこれらを選択しています高度な機能をサポートしているため、Cを無視する言語です。Cから始めるように言います。VB.NETまたはJavaで高度なことをしているときにポインタの概念を学ぶのはもったいないと言います= Cでは不可能です。

どう思いますか?

更新

私がGoogleで読んだコメントは次のとおりです。

  1. 初期のコンピューターは遅すぎて最適化されていませんでした。

  2. ポインタを使用すると、アドレスに直接アクセスでき、関数呼び出しでアドレスのコピーを作成する代わりに、時間を節約できます。

  3. ポインタを使用すると、セキュリティが大幅に低下します。そのため、JavaおよびC#にはポインタが含まれていませんでした。

これらと私が見つけたもののいくつか。私はまだいくつかの貴重な答えが必要です。よろしくお願いします。

92
niko

当時、開発者たちはずっと金属に近いところで働いていました。 Cは本質的にアセンブリの上位レベルの置き換えであり、ハードウェアに可能な限り近いので、コーディングの問題を効率的に解決するためにポインタが必要なのは当然のことでした。ただし、ポインターは鋭利な道具であり、不用意に使用すると大きな損傷を引き起こす可能性があります。また、ポインタを直接使用することで、当時は問題ではなかった多くのセキュリティ問題の可能性が開かれます(1970年、インターネットはいくつかの大学で数十台のマシンで構成されていました。 ...)、それ以来、ますます重要になりました。したがって、今日、高レベルの言語は、生のメモリポインタを回避するように意識的に設計されています。

「VB.NetまたはJavaは不可能)の高度なこと」と言うと、控えめに言っても非常に限定された見方が示されます:-)

まず第一に、これらのすべての言語(アセンブリを含む)はチューリング完全であるため、理論的には、1つの言語で可能なことはすべて可能です。 VB.NetまたはJavaコードがコンパイルされて実行されたときに何が起こるかを考えてください。結局、それはマシンコードに変換(またはマッピング)されます。マシンが理解します。CやC++などのコンパイル済み言語では、1つ以上の実行可能ファイル/ライブラリとして、元の上位レベルのソースコードと同等のマシンコードの完全なボディを実際に取得できます。VM =ベースの言語の場合、プログラムの同等のマシンコード表現全体を取得するのはよりトリッキーです(不可能でさえあるかもしれません)が、最終的にはランタイムシステムとJITの深い窪みのどこかにあります。

もちろん、特定の言語で解決策を実行できるかどうかはまったく別の問題です。賢明な開発者がアセンブリでWebアプリを書き始めることはないでしょう:-)しかし、これらの高水準言語のほとんどまたはすべてが、膨大な量のランタイムおよびクラスライブラリコードの上に構築されていることを覚えておくと便利です。これは低レベル言語で実装され、通常はCです。

だから質問に行くために、

若者へのポインタに関する知識は重要だと思いますか[...]

ポインターの背後にある概念はindirectionです。これは非常に重要な概念であり、私見のすべての優れたプログラマーは特定のレベルでそれを把握する必要があります。誰かがより高いレベルの言語だけで作業している場合でも、間接参照と参照は依然として重要です。これを理解しないと、非常に強力なツールのクラス全体を使用できなくなり、長期的には問題解決能力が大幅に制限されます。

ですから、私の答えは「はい」です。本当に良いプログラマになりたいのであれば、ポインタも理解する必要があります(再帰も同様です。これは、新進の開発者にとって他の典型的な障害です)。あなたはそれから始める必要はないかもしれません-私は今日では第一言語としてCが最適だとは思いません。しかし、ある時点で、インダイレクションに慣れる必要があります。それがなければ、私たちが使用しているツール、ライブラリ、フレームワークが実際にどのように機能するかを理解することはできません。そして、自分の道具がどのように機能するかを理解していない職人は非常に限られています。十分に公正であるならば、より高いレベルのプログラミング言語でもそれを理解するかもしれません。よいリトマステストの1つは、二重にリンクされたリストを正しく実装することです。好きな言語でそれを実行できれば、間接性を十分に理解していると主張できます。

しかし、他に何もなければ、私たちが持っているとんでもないほど単純なツールを使用して信じられないほどのものを構築することができた古いプログラマーに対する敬意を学ぶためにそれを行う必要があります(現在のものと比較して)。私たちは皆、巨人の肩の上に立っており、私たち自身が巨人であると偽るのではなく、これを認めることは私たちにとって良いことです。

129
Péter Török

あなたは違う必要があると思います。

Javaおよびその他の高水準言語では、ポインターは削除されませんでした。彼らがしたことは、単純なポインタ演算を取り除くことでした。

実際、Javaでもprotectedおよびrestrictedポインタ演算を許可しています:配列アクセス。単純な古いCでは、配列アクセスは他にありません)それは、あなたが何をしているのかを明確に伝えるための、別の表記法、つまり構文上の砂糖です。
それでも、_array[index]_は*(array+index)と同等です。そのため、これは_index[array]_と同等ですが、一部のCコンパイラは警告を出す場合があると思います。
当然のことですが、_pointer[0]_は_*pointer_と同等です。これは、「配列へのポインタ」が配列の最初のエントリのアドレスであり、後続の要素のアドレスがインデックスを追加することによって計算されるためです。

Javaでは、単純なポインタ演算(参照と逆参照)はもう存在しません。ただし、ポインタは存在します。それらは参照と呼ばれますが、それが何であるかは変わりません。そして、配列アクセスはまったく同じです。アドレスを見て、インデックスを追加し、そのメモリ位置を使用します。ただし、Javaでは、そのインデックスが最初に割り当てた配列の境界内にあるかどうかをチェックします。そうでない場合は、例外がスローされます。

Javaアプローチの利点は、コードがないので、任意のバイトを任意のメモリ位置に盲目的に書き込むことです。これにより、安全性とセキュリティが向上します。バッファオーバーフローなどの場合、ランタイムがそれを行います。

これの欠点は、それが単にそれほど強力ではないということです。 Cでメモリセーフプログラミングを行うことは可能です。Javaでの安全でないプログラミングの速度と可能性から利益を得ることは不可能です。

実際には、ポインターやポインター演算については難しいことは何もありません。それらは通常、複雑な方法で説明されますが、すべてのポインタは1つの巨大な配列(メモリ空間)へのインデックスですが、値を参照することはすべて、それを見つける場所のインデックスを提供し、逆参照はすべてルックアップすることです指定されたインデックスの値。 (これは、値がタイプによってメモリ内で異なるサイズであることを考慮に入れていないため、これは少し単純化されています。しかし、それは実際の概念の一部ではなく、状況の詳細です)

私見、私たちの仕事の誰もがそれを理解できるはずです、そうでなければ彼らは単に間違った分野にいます。

39
back2dos

ポインタの概念は、一般的なコンピュータプログラミングの知識体系において重要です。概念を理解することは、その言語が直接それをサポートしていない場合でも、プログラマーになる予定の言語や任意の言語のプログラマーに適しています。

ポインターは、データ構造(リンクされたリスト)およびデータベース設計(外部キー)で使用されます。

VBやC#などの言語では、メソッドへの「参照」によってデータを渡すことができます。これは、ポインタの一種と考えることができます。

メモリ内のデータが割り当てられている場所(スタックとヒープ)を理解することは、依然としてアルゴリズムの効率にとって重要です。

私の意見では、基本を正しく学ぶことは重要です。

24
NoChance

はい、はい、はい、はい、はい!!!

基本がわからない場合は、あなたがたどり着く本当に難しい、奇妙な、困難で複雑な問題を解決することはできません。

そして、あなたが基本を本当によく理解していれば、あなたは就職市場ではるかに市場性があります。


私は10年間プログラミングをしているchapと一度作業しましたが、ポインターがどのように機能するかわかりませんでした。私(ずっと若い)は彼を教育するホワイトボードで何時間も過ごした。それが私の目を開きました。彼はNO IDEA非常に多くの基本的なことについて持っていませんでした。

できる限り知ってください。

19
quickly_now

はい、理解は重要です。

数か月前、私はC#でプログラミングしていて、リストのコピーを作成したいと思っていました。もちろん、私がしたことはNewList = OldList;、次にNewListの変更を開始しました。両方のリストを印刷しようとしたとき、NewListOldListへのポインタであり、コピーではないため、実際にはOldList allを変更していたので、どちらも同じでしたに沿って。それを理解するのにそれほど長くはかかりませんでしたが、私のクラスメートの何人かはそれほど速くなく、なぜこれが起こっているのか説明されなければなりませんでした。

例:

List<int> a = new List<int>();
a.Add(2);
a.Add(9);
a.Add(8);
a.Add(1);
List<int> b = new List<int>();
b = a; //Does not make a copy, b is just a synonym!
b.Sort();
for (int i = 0; i < a.Count; i++)
{
    Console.WriteLine("a: " + a[i] + " b: " + b[i]);
}

そしてもちろん、結果は次のようになります。

a: 1 b: 1
a: 2 b: 2
a: 8 b: 8
a: 9 b: 9

それらの使用方法を知ることはそれほど重要ではありませんが、それらを理解することは重要です!

18
Bojan Kogoj

CマスターのDennis RitchieがCでポインターを導入したのはなぜですか?

ポインタは、さまざまな方法で使用できる非常に強力なメカニズムだからです。

そして、なぜVB.NETやJavaまたはC#のような他のプログラミング言語がそれらを排除したのですか?

ポインターは非常に危険なメカニズムであるため、さまざまな方法で誤用される可能性があります。

プログラマーはポインターについて学ぶべきだと思いますが、教育の観点から、それらを早期に紹介することは賢明ではありません。その理由は、それらが非常に多くの異なる目的に使用されているためです。特定の状況でポインターを使用している理由を初心者に伝えるのは困難です。

以下は、ポインターが使用される不完全なリストです。

  • 動的割り当て(_new T_)
  • 再帰的なデータ構造(_struct T { T* next; /* ... */ };_)
  • 配列のイテレータ(for (T* p = &a[0]; p != &a[0] + n; ++p) { ... }
  • オブジェクトへの共有アクセス(_T* new_pointer = existing_pointer;_)
  • サブタイプポリモーフィズム(_T* pointer_to_base = pointer_to_derived;_)
  • 参照によるレガシー呼び出し(mutate(&object);
  • オプションのタイプ(if (p) { /* ... */ }

これらの概念すべてに単一のメカニズムを使用することは、経験豊富なプログラマーの力と優雅さの両方と、プログラミングに不慣れな人にとって大きな混乱の可能性があることを示していることに注意してください。

14
fredoverflow

概念へのポインタ!=算術へのポインタ!=構文へのポインタ

ディープ/シャローコピーの理解、参照渡し、値渡しなどが必要な場合(および必要な場合)、最初の問題は常に重要です。他の2つは、使用する言語で使用できる場合にのみ重要です。

14
Alien Life Form

どうして?フォームデザイナとコードジェネレータを使用して巨大なシステムを作成できます。それで十分ではありませんか? (アイロニー)

そして今、真剣に、ポインタは多くの領域でプログラミングの重要な部分ではありませんが、内部がどのように機能するかを人々に理解させることができます。そして、内部がどのように機能するかを理解している人がいない場合、SQL2020、Windows 15およびLinux 20.04が、JavaScriptでIDEを介して生成されたコードを使用して、30層以上の抽象化を実行するガベージコレクションされた仮想マシンで記述される状況になります。

これは間違いなく私が見たいものではありません。

ですから、そうする必要があります。

12
Coder

JavaもC#もポインタを排除していません。それらはほとんど同じ参照を持っています。排除されたのは、ポインタの算術です。これは入門コースでは省略できます。
ポインタや参照の概念なしでは重要なアプリケーションは実行できないため、教える価値があります(動的メモリの割り当てはそれらなしでは実行できません)。

C++とJavaでは次のことを考えてください。C#でもそれほど変わらないと思います。
aClass *x = new aClass();
aClass x = new aClass();
ポインタと参照の間にそれほど大きな違いはありませんよね?
必要でない限り、および高レベルモデルでプログラミングする場合は、ポインター算術を回避する必要があるため、それほど問題はありません。

7
Petruza

プロのプログラマーはポインターをマスターする必要があります。

プログラミングについて知りたい人は、その存在と意味について学習する必要がありますが、必ずしもそれらを使用する必要はありません。

プログラミングを介して個人的な問題を解決したい人々(私のように、Pythonスクリプトを多く使用する)は、それらをまったく無視することができます。

まあ、それは私の意見です...; o)

6
heltonbiker

絶対に[〜#〜]はい[〜#〜]!プログラムを行うすべての人は、ポインタと間接参照を理解する必要があります。

ポインターは、すべての言語で大量のデータアクセスが行われる方法です。ポインターは、すべてのマイクロプロセッサーのハードウェア機能です。 Javaなどの高水準言語、VB&C#は、基本的に、参照を持つ言語のユーザーからのポインタへの直接アクセスを制限します。参照は、言語のメモリ管理スキームを介してオブジェクトを参照します(メタデータまたはメモリテーブルの単なる数値など)。

ポインタがどのように機能するかを理解することは、コンピュータが実際に機能する方法を理解するための基本的なです。ポインタは参照よりも柔軟で強力です。

たとえば、配列がインデックス0から始まる理由は、配列は実際にはポインター演算の省略形であるためです。ポインターがどのように機能するかを学ばなければ、多くの初心者プログラマーは配列をまったく取得しません。

int a, foo[10];
foo[2] = a;

ポインタ演算の2行目は次のようになります。

*(foo + sizeof(int) * 2) = a;

ポインタを理解しないと、メモリ管理、スタック、ヒープ、または配列さえ理解できません。さらに、関数とオブジェクトがどのように渡されるかを理解するには、ポインタと逆参照を理解する必要があります。

TL:DR:ポインタを理解することは、コンピュータを実際に機能させるための基本です

3
CyberSkull

可変アドレスポインターは、より一般的な間接化の概念の特定のケースです。インダイレクションは、デリゲートやコールバックなどの多くの構成要素で、ほとんどの(すべての?)現代言語で使用されています。間接参照の概念を理解すると、これらのツールをいつどのように最適に使用するかを知ることができます。

3
Dave Nay

プログラマーが直接実行しているハードウェアを扱うことが少なくなったため、ポインターを扱う必要性がなくなったという事実に端を発していると思います。たとえば、専用ハードウェアが備えていた640バイトのメモリモジュールのシーケンスに完全に適合するように、リンクリストのデータ構造を割り当てます。

ポインタを手動で処理すると、エラーが発生しやすくなり(メモリリークと悪用可能なコードにつながります)、正しい作業に時間がかかります。したがって、JavaおよびC#などはすべて、仮想マシン(VM)を介してメモリとポインタを管理します。これは、生のC/C++を使用するよりもおそらく効率が劣りますが、VMは常に改善されています。

C(およびC++)は、特にハイパフォーマンスコンピューティング、ゲーム、および組み込みハードウェアの分野で、依然として広く使用されている言語です。 Javaの参照への移行(ポインターと同様の概念)は非常に簡単で、最初のNullPointerException(実際にはNullReferenceExceptionと呼ばれるはずですが、余談です)を見ても失われなかったので、私は個人的にポインターについて学びました。 。

ポインタがまだ多くのデータ構造などを支えているので、ポインタの概念について学ぶことをお勧めします。次に、作業したい言語を選択します。NPEのようなものが表示されれば、実際に何が起こっているかがわかります。 。

2
Martijn Verburg

これは客観的な真実です:

一部の言語はダイレクトメモリアクセス(ポインター)をサポートしていますが、一部はサポートしていません。それぞれのケースには正当な理由があります。

  1. 誰かがここで言ったように、Cの時代には、自動メモリ管理は今日ほど精巧ではありませんでした。とにかく人々はそれに慣れていました。当時の優れたプログラマーは、私たちの世代よりもコンピュータープログラムを深く理解していました(私は21歳です)。彼らは、パンチカードを使用し、メインフレームでのコンパイル時間を待っています。彼らはおそらく、コードのあらゆる部分が存在する理由を知っていました。

  2. Cのような言語の明らかな利点は、プログラムをより細かく制御できることです。あなたは実際にいつ必要それを、最近ですか? OS関連のプログラムやランタイム環境などのインフラストラクチャアプリケーションを作成する場合のみ。優れた、高速、堅牢、信頼性の高いソフトウェアを開発したい場合は、自動メモリ管理が最適です。

  3. 実際のところ、直接メモリアクセスは、ソフトウェア開発の歴史の中で主に悪用されてきました。人々はメモリリークを起こすプログラムを作成していましたが、冗長なメモリ割り当てのために実際には遅くなりました(Cでは、単一の割り当てごとにプロセスの仮想メモリ空​​間を拡張するのは簡単で一般的です)。

  4. 最近では、仮想マシン/ランタイムは、メモリの割り当てと解放において、99%のプログラマよりもはるかに優れています。その上、適切なタイミングと場所で割り当てられたメモリを解放することに(ほとんどの場合)専念していないため、プログラムに必要なフローをさらに柔軟にすることができます。

  5. 知識も。プログラマーが、自分がプログラムする環境がどのように実装されているかを知っているのは、すばらしいと思います。必ずしも細部に至るまでではなく、全体像を把握しています。

(少なくとも)ポインタの動作を知ることは興味深いと思います。ポリモーフィズムの実装方法を理解するのと同じです。プロセスがメモリを取得する場所と方法。これらは、個人的に常に私にとって興味のあることです。彼らが私をより良いプログラマーにしてくれたと正直に言うことができますが、彼らが優れたプログラマーになりたいと思う人のための教育的必要であるとは言えません。どちらの場合でも、多くのことを知ることで、多くの場合betterが作成されます。

  1. 私の見方では、JavaまたはC#またはそのようなものでアプリケーションを作成することを求められている場合は、適切な設計と実装手法に焦点を当てる必要があります。テスト可能なコード、クリーンなコード、柔軟なコード。

たとえ細かいことすべてを知らなくても、あなたが作成したものを、誰かが単純にパフォーマンスの高いものに変更できるからです。そして、適切でクリーンでテスト可能な設計が整っていれば、それはたいてい難しい仕事ではありません(そしてそれが通常はほとんどの作業です)。

私が高レベルの言語のアプリケーションのために誰かを雇うことを探しているインタビュアーであったなら、それらは私が最も興味を持っていることでしょう。

低レベルの知識はボーナスです。これは、デバッグや、場合によっては少し優れたソリューションを作成するのに適しています。それはあなたを専門的に興味深い人にします。それはあなたにあなたの職場でいくつかの尊敬を与えます。

しかし、今日の世界では、それは神聖な要件ではありません。

0
Yam Marcovic