こんにちは､ そしてお帰りなさい｡ この講義では､ 動的なメモリ割り当てについてお話したいと思います｡
これはポインタに直接関係するもので､ ポインタにしか採用できない｡
では､ さっそく始めましょう｡
そのため､ cで変数を定義すると､ コンパイラはデータ型に基づいて自動的に適切な量のストレージを割り当ててくれるのです｡
私たちは､ このことをずっと見てきました｡ 整数､ 浮動小数点､ 倍数を作るとき､ メモリを割り当てる必要はない｡
コンパイラがやってくれるんです｡ 実際にメモリが確保されるのです｡
ちなみにポインターも同じです｡ ポインターを作成すると､ ポインターの型であるアドレスが格納されるように､
メモリが割り当てられます｡
これで､ そのアドレスにメモリが確保されたことにはならない｡
これまで､ ポインターにデータを代入するときは､
必ず既存の変数を代入していた｡
つまり､ ポインタにデータを代入したい場合､
その変数にはすでにメモリが割り当てられているので､ アンパサンドオペレータのアドレスを使用したわけです｡
しかし､ ポインタを作成する際に､ operatorのアドレスを代入するのではなく､
動的にメモリを確保したい場合はどうでしょう｡ それが､ この講演全体の趣旨です｡
そのため､ プログラムの実行中に動的にストレージを確保できることが望ましい場合が多い｡
必要な時に必要な分だけメモリを確保する｡
ファイルからメモリ上の配列にデータセットを読み込むようなプログラムの場合､
3つの選択肢があります｡
コンパイル時に可能な最大数の要素を含むように配列を定義することができ､
それは固定サイズである｡
50個の要素を持つ配列を定義すると､ 50個の要素しか含まれないことになります｡
コンパイラが50と判断すると､
実行時にその分のメモリを確保することになる｡
可変長の配列を使用すると､ 配列のランタイムの大きさをディメンションにすることができます｡
可変長配列については､ C11までサポートされないという話を少ししました｡
実際にはC11を削除して､ C99を追加しているんです｡
ここで変数を入れることができます｡
しかし､ これらはまだ固定サイズのようなものです｡ なぜなら､
可変リンク配列の意味するところは､ サイズを変数で渡すことができるということだからです｡
でも､ まだ静止画なんです｡
あるいは､ 必要なときに動的にアレイを割り当てるのがベストな選択です｡
そして､ これを行うために呼び出すことができるさまざまなC関数があります｡
だから､ 動的にメモリを確保できるのはとても便利なことだと思います｡
つまり､ 最初のアプローチでは､ これまでずっと､ 配列であろうとデータ型であろうと､
サイズが固定されています｡
配列に正しく入る最大数の要素を含むように､ 配列を定義する必要があります｡
つまり､ int dataArray [1000]のようにするわけです｡
しかし､ これはデータファイルが1000以上の要素を含むことができないということを意味します｡
そうすると､ プログラムが壊れてしまうんです｡
だから､ 読み込むファイルが大量のデータを持っていないことを祈るしかない｡
大きなファイルセットや大きなファイルでは､ プログラムが動作しません｡
また､ 大きなファイルを扱う場合は､ アレイを大きくして戻らなければなりません｡
サイズを変えなければならないのに､
その上で再コンパイルしなければならないのは､ コンパイル時間です｡
どのような値を選択しても､ サイズが固定されているため､
将来的に再び同じ問題に遭遇する可能性があります｡
このサイズはコンパイル時に決定され､ プログラムを実行する際には調整されません｡
ダイナミックに変化しないのです｡
動的メモリ割り当て機能を使えば､ 必要な時に必要な分だけストレージを確保することができます｡
この方法だと､ プログラムの実行中にメモリを確保することができます｡
だから､ そのメリットを考えてみてください｡ まず､ 使わないかもしれない大量のメモリを作らず､
必要な分だけ作ることができます｡
そして､ さらに必要な場合は､ さらに割り当てることができます｡
戻って再コンパイルしてサイズを変更する必要はないのです｡
だから､ 動的なメモリ割り当てが有効なのです｡
これはポインタの概念に依存し､ コードにポインタを使用する強い動機付けとなります｡
ポインタの利点について説明しましたが､
皆さんは､ ポインタはクールな概念だけど､ なぜ使う必要があるのだろう､
と思ったかもしれません｡
C言語は効率的な言語であり､ 大量のメモリを使用しないことが重要なのです｡
cは組み込みシステム､ リアルタイムプログラミングで動作するわけですが､
必要性に応じて使用するメモリを制限することができるので､ これが理由の一つです｡
そこで､ 動的メモリ割り当てでは､ データを格納するためのメモリを､ プログラムの実行時に動的に割り当てることができる｡
メモリを動的に割り当てるのは､ ポインタが使えるからこそ可能なのです｡
アドレスがあり､ ポインタがどこを指しているかを変更できるため､
メモリの再調整が可能です｡
製品プログラムの大半は､ 動的メモリ割り当てを使用します｡
cでコードを書いている人は､ これを使うことになる｡
初心者でもダイナミックメモリアロケーションを使うことになる｡
ほとんどの便利なプログラムは､ このコンセプトを採用しています｡
データを動的に割り当てることで､ タスクに必要なデータ量を保持するのに十分な大きさのポインタを実行時に作成することができ､
メモリの無駄を省くことができるのです｡
Vital.
また､ ヒープとスタックの話もしなければなりません｡
プログラム中のメモリは､ スタックにデータを格納する方法と､
ヒープにデータを格納する方法の2種類のデータ構造をとることができます｡
動的メモリ割り当てでは､ ヒープ上にすべてを確保します｡
これらがどのように構成されているかは詳しく説明しませんが､ 基本的にはそうです｡
データをヒープに格納すると､ より多くの変更が可能になります｡
データオブジェクトのサイズを任意に変更することができ､
ヒープでメモリを確保すると､ プログラム全体に張り付くようになるのです｡
スタックを使うと､ より制限されます｡
スタックは､ 関数の引数やローカル変数など､ あらゆるものに使用されます｡
そこにそれらがすべて保存されているのです｡
そして､ それがコールスタックの話になったわけです｡
メソッドとファンクションに注目したのです｡
メソッドはたまに使うけど､
メソッドって本当はオブジェクト指向の用語だから､ 関数ね｡
関数に関連するものはすべてスタック上に作成されます｡
つまり､ 関数を実行すると､ スタックに積まれるということです｡
ローカル変数はスタックに置かれる｡
機能を終了すると､ すべてが削除されます｡
そのため､ スタック上に配置されたメモリはあまり長くは残らない｡
これが､ メモリを動的に割り当てるときにヒープ上にある理由の一つです｡
いつ使うか､ いつ使わないかをコントロールするために､
メモリを割り当てたり削除したりします｡
スタックにあるものは､ 自分でコントロールできない｡ 自動的に削除され､ 自動的に割り振られる｡
つまり､ ローカル変数やmainなどの関数内の変数は､
スタックなどに作成されるのです｡
ヒープ上のメモリは別物で､ プログラマーであるあなたがコントロールするものです｡
ヒープ上にメモリを確保した場合､ 確保したメモリがいつ不要になったかを把握するのは自分次第なので､
メモリを削除する必要があります｡
自分が使わなくなったスペースは､
解放しなければなりません｡ そして､ メモリは非常に希少な資源であるため､
これは重要なことです｡
現在では､ 12ギガ､ 16ギガと､ コンピュータを動かすためのメモリがたくさんあります｡
しかし､
デバイス上で動作する組み込み用のプログラムでは､ 必ずしもそれほど多くのメモリを持っているわけではありません｡
そのため､
メモリの使用量を制御し､ 使い終わったらメモリを解放して他のアプリケーションが使えるようにしたいのです｡
ここでも､ 低レベルの組み込み型システムにおいてより重要である｡
しかし､ これは多くの言語にはない自由さです｡ この能力は､ プログラマーによってマネージャーメモリを制御することができ､
プログラムをより効率的に､ より速くすることができます｡
そこで､ 次回の講義では､ 実際にどのようにして､ どのような関数を呼び出すことができるのか､
についてお話します｡ もちろん､ メモリを確保したり､ メモリを解放したりするために呼び出すことのできるさまざまな関数があります｡
ありがとうございます｡