プログラミング作法に関する世界観3B(データ操作)です。Cの世界観3(データ構造)も参照のこと。
僕は、変数には二種類の使われ方があると思います。
1.一時的な記憶領域。コードブロックの中で、ローカル変数として宣言される。
2.各関数の間で共有されるデータ構造。グローバル変数あるいは引数での構造体のポインタとして定義される。あるいはオブジェクト指向ではクラスやオブジェクトのメンバ変数がこれに相当する。
この2種類は、「スコープが消えても残り続けるかどうか」という違いがある。ローカル変数はスコープから抜ければ消え去る。構造体のポインタはスコープが消えても残り続ける。
C言語でも、C++などのオブジェクト指向言語でも、この2種類があります。これを分かっておくことで、Linuxカーネルなどのコードを理解しやすくなります。
また、もう一つのやり方があるとしたら、
3.関数の呼び出し元と呼び出し先の間でやり取りされる変数。引数や返り値あるいは戻り値と呼ばれる。
があるでしょう。
後日注記:このほかに、たとえばWindows APIなどでは、
4.システムとやり取りをするために使う。たとえばウィンドウクラスにコールバック関数となるウィンドウプロシージャ名や、メニューとなるリソース名を登録したり、ウィンドウのインスタンスやデバイスコンテキストのハンドルを取得する。
などといった変数の使い方があります。
2022.12.09編集
プログラム、特にゲームのようなプログラムに言えることとして、外部に設定ファイルやデータファイルを作り、キャラクターの状態やゲームの進行状況などを保存する、といったことがあります。
普通にPerl/CGIでプログラムを組んでいると、変数とrand()関数のようなランダム数値だけで、おおざっぱなルーチンは簡単に作れますが、これだと、毎回実行するたびにキャラクターの能力やヒットポイントが最初に戻ってしまいます。
こういう時、Perl/CGIでは外部に設定や状態を保管するデータファイルを作り、それを読み出します。
こうしたデータファイルを作る時は、Perlでは文字列を分割するsplit()関数を用いて読み出し、書き込む時はjoin()関数を使うと便利です。その上で適切に読み込みオープン・書き込みオープンを使い分けながら、データファイルを読み書きしましょう。
コードとファイルも参照のこと。
また、C言語などでよくみられる方法として、「定数をフラグとして扱う」というのがあります。
フラグは、論理和や論理積で、「FLAG_ONE | FLAG_TWO」とか、「FLAG_ONE & FLAG_TWO」などとし、if文やswitch文などで、こうしたフラグの「論理的な合一と複合を示す値」を取るのです。
この他、C言語の論理演算では、三項演算子「~ ? ~ : ~」などもよく使われます。
また、定数や構造体の型はヘッダファイルに記述し、それを使う全てのC言語ソースファイルでそのヘッダファイルをincludeします。場合によっては、小さな記述であればヘッダファイルに関数のコードの実体を記述することもあります。
プログラミングの初心者向けのことを言うと、「関数と制御の中でデータを扱うことが基本」であると言えます。
関数とは、ライブラリ関数のことです。制御とは、if文やfor文のことです。データとは、変数やリテラルのことです。
if文やfor文の中で変数を扱いながら、システムに存在するAPI関数を呼び出すことができれば、それでプログラミングは簡単にできています。
それ以上は、ルーチンワークです。どのような設計でルーチンを実行するか、ということが基本になります。ですが、それはやっている中で変えていけばいいとか、必要に応じて書き直していけばいいのです。
基本として言えるのは、「データをどのように扱うか」ということです。データを扱うこと、データを渡すこと、データを参照すること、データを変更すること、それ自体がプログラミングなのだと僕は思います。
また、プログラミングを行う上で、型は大切です。それは、データを扱う上で、「どのような種類のデータを扱うか」が決まってくるからです。
最近は動的型付け言語というものが流行っていて、動的にその場その場の変数の内容に応じて、型をダイナミックバインディングできる言語もあります。
ですが、僕は静的型付けの方が好きです。それは、「きちんと正しくコードが動くこと」を考えているからです。
動的か、静的かという永遠の論争をするよりも言えることは、動的型付けの言語であっても、「そのデータが文字列か数値か特定のクラスか」を考える、ということは、どんな言語でも変わらないということです。
データを扱う上で、そのデータがどんな種類の型であるかを、意識するようにしましょう。そこで、「データをどのように処理したらいいか」も同時に決まってくるでしょう。
型も参照のこと。
Javaのようなガーベッジコレクションを搭載した言語が増えている中で、時代遅れだと言われるかもしれませんが、C/C++のプログラミングをもし行うのであれば、「プログラムの中で確保したものはプログラムの中で廃棄する」ということを守りましょう。
これは、単にmalloc()とfree()だけには限りません。多くのC/C++フレームワーク、特にWindowsプログラミングなどを行う場合であっても、プログラムの中で確保したリソースは、プログラムの中で廃棄しなければなりません。GetしたものはReleaseしなければならないのです。
ローカル変数などは、スタックで管理されるため、スコープを終えれば自動で削除されますが、malloc()で確保した領域は、ヒープで管理されるため、「明示的に解放しなければメモリリークが起きてしまう」可能性があります。
よって、プログラミングを行う上で必要となるのは、
必要事項 | 説明 | 例 |
---|---|---|
1.演算子 | 計算や論理の一致・適合を行う。 | +や==など |
2.変数の格納 | データを確保・参照・変更する。 | varやstructなど |
3.条件付き制御フロー | 条件に応じて処理を行う。 | if文やfor文など |
4.関数呼び出し | システムに存在する関数を呼び出す。 | printf()やecho()など |
5.関数の定義 | 呼び出すための関数を自分で作成する。 | ルーチンの作成 |
6.メモリの管理 | 確保したリソースをきちんと廃棄する。 | スタックとヒープ |
7.外部ファイルへの依存 | データを永続化する。 | 設定ファイル、データベースなど |
などとなります。これらがきちんとできれば、あなたは一流プログラマです。
また、僕が思うに、プログラミングはデータ構造が肝だと思います。
配列・ベクター、連結リスト、スタック、キュー、ハッシュテーブル、ツリー、グラフのようなデータ構造が、プログラミングをマスターする上では欠かせないものとなってきます。
たとえば、C++やPythonやJavaでプログラミングを行う際、このようなデータ構造はある程度最初から用意されていますが、それを活用しなければコーディングは成り立ちません。また、ツリーや連結リストなどは自分で作らなければいけないこともあります。純粋な連結リストやツリーではなく、その亜種のようなデータ構造を作る必要があることは多々あります。
アルゴリズムやルーチン、あるいはモジュールを自分で書いたりする時にも、データ構造をいかに扱うかが大切になるでしょう。
データ構造も参照のこと。