\r\n\r\n

プログラマーズポインターの紹介

あなたが気づいているかどうかは別として、あなたが使っているプログラムの大部分は何らかの形でポインターを使用しています。プログラマーとして、ポインタの仕組みを理解する必要がある...。

意識しているかどうかにかかわらず、あなたが使っているプログラムのほとんどは何らかの形でポインターを使用しています。おそらく皆さんもどこかでNullPointerExceptionに遭遇したことがあるでしょうし、プログラマであれば、自分で実装しないまでも、ポインタを使ったコードを書くことが多いはずです。

今日はポインタの仕組みを紹介しますので、プログラミング入門で配列とリストの仕組みを理解しておくとよいでしょう。今回はいつもより理論的な内容になりますが、頑張ってください!ポインターはとても複雑なんです。

コードのコンパイル

ポインターを理解する前に、コードがどのように構築され、実行されるかを理解する必要があります - おそらく既にご存知でしょう。このセクションでは、ほとんどの言語に適用できるが、必ずしもすべてに適用できるわけではない、かなり一般的な記述を行う。

初心に帰ろう。すべてのコンピュータはバイナリを使っている。バイナリは1と0の組み合わせで、私たちが知っている現代技術を構成している。バイナリコードで何かを書くのは非常に難しい(ファイルは非常にわかりにくい)。なぜなら、これらは中央処理装置やCPUが動作するために必要なオリジナルの命令だからである。これはマシンコードです。

マシンコードの次のステップはアセンブリです。これは人間が読めるフォーマットです。プログラミングはまだ複雑ですが、これは可能です。アセンブリは、タスクを実行する一連の単純なコマンドで構成されており、低レベルのプログラミング言語として知られています。複雑なプログラムを書くことは可能ですが、抽象的な概念を表現することは難しく、多くの配慮が必要です。

多くのビデオゲームや高性能アプリケーションには、アセンブリ言語で書かれたロジックがあります。しかし、大半のプログラミングプロジェクトでは、アセンブリの知識はまったく必要ありません。

では、機械語は書くのが大変で、アセンブリプログラムはプログラムするのが大変だとしたら、何を使ってコードを書けばいいのだろう?そこで便利なのが高級言語です。高級言語はプログラムを簡単に書くことができる。母国語に近い言語でプログラミングができ、複雑なアルゴリズムも簡単に表現できる。皆さんは多くの高級言語をご存知でしょう(そして、その言語で書かれたプログラムも必ずあるはずです)。

  • ベーシック
  • C++
  • 歯切れの悪い言葉

これらの言語は現在では非常に古く、多くは1950年代初頭に開発されたものです。PHPやPythonをはじめ、現代のプログラミング言語はほとんどすべて高級言語です。さらに多くの言語が日々発明されていますが(今は十分でしょうが)、コンピュータが機械語を必要とするなら、一体どのようにしてあなたのコードは正しく動くのでしょうか?

そこで活躍するのがコンパイルです。コンパイラは、高レベルのコードを実行可能な形式に変換するプログラムです。これは他の高級言語である場合もあるが、通常はアセンブリ言語である。PythonやJavaなど一部の言語では、コードをバイトコードと呼ばれる中間段階に変換する。これは後でもう一度コンパイルする必要があり、通常はプログラムの実行時など必要なときに行います。これはジャストインタイムコンパイルと呼ばれ、非常に人気がある。

メモリ管理

プログラミング言語の仕組みがわかったところで、高級言語におけるメモリ管理について見ていきましょう。これらの例では、疑似コード(特定の言語で書かれたコードではなく、正確な構文ではなく、概念を示すために使用される)を使用します。今日、これは最高の高級言語であるC++に最も似ているでしょう(私の意見です)。

このセクションでは、RAMの仕組みを理解しておくと役に立ちます。

ほとんどの言語には変数というデータが格納される容器があります。データ型は明示的に定義する必要があります。動的型付け言語(PythonやPHPなど)の中には、これを処理してくれるものもありますが、それでもやらなければなりません。

変数があるとします。

int myNumber;

このコードでは、myNumberという変数を宣言し、そのデータ型に整数を与えています。コンパイル後、コンピュータはこのコマンドを次のように解釈します。

空のメモリを探し、整数を格納するのに十分な大きさの領域を確保する。

このコマンドを実行すると、そのメモリビットは他のプログラムから使用できなくなります。まだデータは入っていませんが、変数myNumberのために予約されています。

では、変数に値を代入してみましょう。

myNumber = 10;

そのため、コンピュータは予約されたメモリー位置にアクセスし、そこに保存されているすべての値を新しい値に変更します。

さて、これは良いことなのですが、メモリロケーションはどのように確保されるのでしょうか?プログラムが好きなだけメモリを確保すると、RAMがすぐに一杯になってしまい、システムの動作が非常に遅くなってしまいます。

この潜在的な問題を回避するために、多くの言語では、スコープ外の変数を破棄する(つまり予約したメモリ位置を解放する)ためのゴミ箱を実装しています。

スコープとは何か、なぜスコープが重要なのか、疑問に思われるかもしれません。スコープは、変数やプログラムが使用するメモリの制限と寿命を定義します。どのコードも変数にアクセスできないとき(つまり、ゴミ収集人が介入したとき)、変数は「アウトオブスコープ」になります。一例として

function maths() { int firstNumber = 1;}int secondNumber = 2;print(firstNumber + secondNumber); // will not work

このサンプルはコンパイルできません。変数firstNumberはmaths関数の中にあるので、そのスコープです。宣言された関数の外からアクセスすることはできません。これはプログラミングの重要な概念で、ポインタを使うにはこの概念を理解することが不可欠です。

このように、メモリを扱う方法をスタックと呼びます。大半のプログラムがそうなっているのです。ポインターを理解しなくても使えるし、構造もかなりしっかりしている。スタックの欠点はスピードです。コンピュータはメモリを確保し、変数を記録し、ゴミの回収を実行する必要があるため、オーバーヘッドは小さい。これは小規模なプログラムには最適ですが、高性能なタスクやデータ量の多いアプリケーションではどうでしょうか。

入力:ポインタ。

ポインタ

一見すると、ポインターはシンプルに聞こえます。メモリ上の位置を参照(指し示す)するものです。スタック上の「普通の」変数にとっては、それほど違いはないように思えるかもしれませんが、信じてください、これは大きな違いなのです。ポインターはヒープ上に格納されます。これはスタックの逆で、整理整頓はできないが、はるかに速い。

スタック上に変数がどのように確保されるかを見てみましょう。

int numberOne = 1;int numberTwo = numberOne;

これは単純な構文で、変数 numberTwo には数字 1 が入っており、代入時にその値が変数 numberOne からコピーされる。

変数の値ではなく、そのメモリアドレスを取得したい場合は、with記号(&)を使用する必要があります。これは演算子のアドレスと呼ばれ、ポインタツールボックスの重要な部分である。

int numberOne = 1;int numberTwo = &numberOne;

numberTwo 変数は、番号 1 をそれ自身の新しいメモリ位置にコピーする代わりに、メモリ位置を指すようになりました。もしこの変数が出力されるとしたら、それは(たとえそれがメモリロケーションに格納されていたとしても)最初の変数ではないでしょう。そのメモリ位置(システムや利用可能なRAMによって異なるが、2167に近いかもしれない)が出力される。メモリ上の位置ではなく、ポインタに格納された値にアクセスするには、ポインタへの参照を解放する必要があります。これは値に直接アクセスするもので、この場合、最初の値になります。ポインタのデリファレンスは次のように行います。

int numberTwo = *numberOne;

再参照演算子はアスタリスク(*)である。

これは理解しにくい概念かもしれませんので、もう一度見てみましょう。

  • 演算子(&)のアドレスには、メモリアドレスが格納されます。
  • デリファレンス演算子(*)は値にアクセスする。

ポインターを宣言する際の構文を若干変更。

int * myPointer;

ここでいうintというデータ型は、ポインタが指すデータの型を意味し、ポインタ自体の型ではありません。

ポインタの意味がわかったところで、ポインタを使って非常に巧妙なトリックを行うことができます。メモリを使用する場合、OSは順番に起動します。ラムは鳩の巣だと思えばいいんです。物を収納するための穴がたくさんあり、1つずつしか収納できません。違うのは、このハトメに番号が振られていることです。メモリを割り当てるとき、オペレーティングシステムは最も小さい数字から始めて作業を行います。乱数の間を飛び交うことはない。

ポインターを使用する場合、配列が既に確保されている場合は、ポインターをインクリメントするだけで簡単に次の要素に移動できます。

ここが面白いところです。関数に値が渡されると(スタックに格納された変数を使用)、その値は関数にコピーされます。もしこれらが大きな変数であれば、プログラムはそれらを2回保存することになります。関数が終了したとき、これらの値を返す方法が必要な場合があります。関数は通常、1つのものしか返せません。では、2つ、3つ、4つのものを返したい場合はどうすればいいのでしょうか?

ポインタを関数に渡すと、メモリアドレスだけがコピーされる(非常に小さい)。これにより、CPUの負担が軽減されますこの関数は、まったく同じメモリ位置に格納されたまったく同じデータを処理できるだけでなく、一度処理が終われば何も返す必要がありません。クリーンでシンプル!

ただし、十分な注意が必要です。ポインターが圏外になっても、ゴミ回収員に回収されることがあります。ただし、メモリに保存されている値は収集されない。これをメモリリークと呼びます。データにはもうアクセスできませんが(ポインタが破壊されたため)、メモリはまだ使っています。これは多くのプログラムクラッシュの原因であり、データが多い場合はひどく失敗することがあります。ほとんどの場合、大きなリーク(システムより多くのRAMを使用)があると、オペレーティングシステムはプログラムを停止させますが、これは望ましいことではありません。

ポインタのデバッグは、特に大量のデータを扱うときやループで作業するときに、悪夢のような状態になることがあります。そのデメリットやわかりにくさは、あなたにとって本当に天秤にかける価値のある性能だと思います。しかし、それらは必ずしも必要なものではないことを忘れないでください。

本日は以上です。複雑なテーマについて、何か有益なことを学んでいただけたなら幸いです。もちろん、私たちはあなたが知るべきことをすべて網羅しているわけではなく、非常に複雑なテーマです。もし、あなたが学習することに興味があるなら、24時間でC++を使うことを強くお勧めします。

もし、これが少し複雑なら、最もシンプルなプログラミング言語のガイドをご覧ください。

また、他のプログラマーと共有したいヒントやコツはありますか? 下のコメント欄にジャンプして、あなたの考えを共有してください。

あなたが興味を持っているかもしれない記事

匿名者
匿名者

0 件の投稿

作家リスト

  1. admin 0 投稿
  2. 匿名者 0 投稿

おすすめ