「関数ポインタ・キャスト・コマンドライン引数」を学んでみる
「C言語」の「関数ポインタ」という、初めて触れる内容の学習を進めていきたいと思います。
「ポインタ」自体が苦手な内容だったので、正直、「またポインタか~」と思っているのですが、何とか学んでいきたいと思います。
「関数ポインタ」って何?
そもそも、この「関数ポインタ」とは何なのか。
「ポインタ」は変数などの格納されている「メモリアドレス」を表すものでした。
ということは、「関数」自体がメモリ内の保存されていて、「関数」が保存されている「メモリアドレス」を表しているのでは?
と思っているのですが、「関数ポインタ」の使い方とは・・・
「関数ポインタ」の仕組みと作り方
「関数ポインタ」は、「関数のポインタを格納する変数」を用意し、その変数に関数の「メモリアドレス」が入っているというイメージは合っていました。
しかし、プログラムの書き方が結構複雑で、
「関数ポインタ」を格納する変数を作るためには、
戻り値のデータ型 (*関数ポインタの変数名)(引数);
のような形で、宣言する必要があり、かなり複雑な書き方になっています。
でも、この「関数ポインタ」ってなんで必要なんだろう。
プログラムを作ってみると、
#include <stdio.h> void dayGreeting(char name[2048]); void nightGreeting(char name[2048]); int main(void) { // 関数ポインタ変数の宣言 void (*greet)(char*); char name[2048] = "satoru"; // 関数ポインタ変数に「dayGreeting」関数を代入 greet = dayGreeting; greet("satoru"); // 関数ポインタ変数に「nightGreeting」関数を代入 greet = nightGreeting; greet("satoru"); return 0; } void dayGreeting(char name[2048]){ printf("こんにちは%sさん\n", name); } void nightGreeting(char name[2048]){ printf("こんばんは%sさん\n", name); }
のようになります。
「関数」を「変数」に入れて使い分けることができるのがメリットみたいですが、実用でこんな機能を使うんだろうか。
いろいろと調べてみると、かなり高度な機能を持つアプリケーションで使われる機能のようで、使われる場面も限定的とのことでした。
自分には全然使える気がしない機能ですが、「どういう機能なのか?」は理解することができました。
「キャスト」の仕組みについて
変数の値を利用するときに重要になるのが、「変数のデータ型」ですが、「変数の値」を「別のデータ型」の値に変換できる機能のことを「キャスト」というそうです。
「int」型の値を「double」型に変換するとどのようになるのかを確かめてみたいと思います。
例えば、
#include <stdio.h> int main(void) { int i = 12; double j = 0.0; j = i; printf("j=%f\n", j); return 0; }
まず、「int」型の「i」の変数を用意し、整数の「12」の値を格納しています。
そして、その「i」の変数を「double」型の「j」の変数に格納すると、
j=12.000000
のようになります。
「コンパイル」のエラーも無く、通常通り実行することができました。
「内部」では自動的に「int」型から「double」型への「データ型」の変換が行われていて、このように自動的に行われる変換のことを「暗黙的変換」と呼ぶそうです。
では、反対に「double」型の値を「int」型へ変換するとどうなるのかというと、
#include <stdio.h> int main(void) { int i = 0; double j = 12.3; i = j; printf("i=%d\n", i); return 0; }
のように「double」型の値に小数点以下の値を設定して、「int」型の変数に値を代入すると、
i=12
のようになり、「小数点以下の値」が無くなってしまいました・・・
エラーも何も出なかったので、「間違った代入」をすると怖いですね。
自動的に変換するのではなく、「明示的にデータ型の変換」をする場合に利用するのが、「キャスト演算子」です。
例えば、
#include <stdio.h> int main(void) { int i = (int)12.3; printf("i=%d\n", i); return 0; }
のように、
(変換するデータ型) 変換する値;
と書くと、データ型の変換を行うことができます。
あまりこういうことを意識していなかったので、変数を使う時に「データ型」が何なのかをちゃんと確認しながら変数を使っていかないといけませんね・・・
コマンドライン引数
「コマンドライン引数」は、これまでに何度も使ってきた、「main」関数に「引数」を渡せる仕組みです。
「main」関数の引数はこれまでは、「void」となっていましたが、
int main(int argc, char *argv[]){
のように、「引数」を指定し、「argc」には、「argv」に渡すデータの「配列の要素の個数」が入ります。
「コマンドライン」と呼ばれる通り、Windowsであれば「コマンドプロンプト」、Macであれば「ターミナル」などの「コマンドから命令を実行できる」アプリケーションで実行します。(よくわかっていないかも・・・)
ただ、デフォルトで「実行ファイル名」が入っているみたいなので、通常通り実行すると、
#include <stdio.h> int main(int argc, char *argv[]) { printf("argc=%d\n", argc); printf("argv[0]=%s\n", argv[0]); return 0; }
のようにプログラムを作って実行すると、
argc=1 argv[0]=C:\TEST.exe
のように表示されます。
「コマンドライン引数」を渡して実行する場合は、
C:\TEST.exe 引数1 引数2
ように「渡したい値」を「半角スペース」を空けながら書いていくと、プログラムで値を受け取ることができます。
例えば、
#include <stdio.h> int main(int argc, char *argv[]) { printf("あなたの好きなゲームジャンルは「%s」です。\n", argv[1]); printf("あなたの好きなゲームジャンルは「%s」です。\n", argv[2]); return 0; }
と書いて、
C:\TEST.exe fps drive
と実行すると、
あなたの好きなゲームジャンルは「fps」です。 あなたの好きなゲームジャンルは「drive」です。
と表示されます。
使い方は理解ができたのですが、「起動モード」の指定などで使えそうですね。
とはいっても、まだ「起動モード指定」が必要なプログラムは書いたことが無いので、さらにいろいろと学んでいきたいと思います。