コマンドラインで変数の値を取得する方法
main関数も,関数
これまで関数には引数があり,戻り値があり,それぞれ型があってやり取りをするという話は
何度か聞いたと思います.ではmain関数はどうなるのでしょうか?
関数であるから,引数も戻り値もあります.では,どこで引数を獲得するのでしょうか?
例えばコマンドライン上で以下のようにタイプしたとします.
c:\>sample.exe 1.52 6.44 9.81 |
main関数に引数を設定すれば,1.52,6.44,9.81をそれぞれ値として取得,プログラム内で利用
することができます.
ソフトウェアを使う,と考えた場合,実行ファイルが起動されているのですが,実行される部分は
main関数ですので,上記のようにデータ(引数)をやり取りする手段が用意されているのです.
方法は,以下の記述法となります.
int main(int argc,char *argv[])
これまでのおなじみの書き方とは違っていることが分かるかと思います.
コラム: main関数の戻り値について(終了コード)
さて,main関数の表記について,いろいろなものを見たことがあると思います.例えば,
main()
void main()
void main(void)
int main()
int main(void)
などでしょうか.厳密に言えば,規格であるANSIに基いた記述をすべきであると言い放って
しまえばそれまでですが,実際にはどれでもコンパイルされてしまいます.(アラートが出る
こともあります.)
ここでソフトウェアがどのように実行されるかを説明します.
ソフトウェア実行ファイルとランタイムライブラリの関係
作成したソフトウェアが直接PCを動かすわけではなく,ソフトウェアの実行により生成された
コマンドがすでに用意されているランタイムライブラリやOSを介して動作するような構造と
なっています.その際に,細かい命令の単位できちんと実行されたか確認するような動作が
含まれているのです.
プログラムの根幹となるmain関数も実行が終わったら,終了したこと自体,ならびに正常に
実行が完了したことをシステムであるOSに伝える必要があるのです.
従って,画面などに表示されることはありませんが,戻り値を返すことが求められるのです.
そのために終了コードと呼ばれるものがあり,正常であれば,0が渡されます.
何も処理しないmain関数であったとしても,以下のように記す必要があります.
C言語 | int main() { return 0; } |
C++言語 | int main(void) { return 0; } |
実はCとC++どちらの表記でも正常にコンパイルされますが,C++でint
main()とした場合は,
暗黙の型としてvoid型として扱われるためなのです.但し,もう少し厳密に説明すると,
int main() | int main(void) | |
C言語 | 引数をチェックしない | 引数がない |
C++言語 | 引数がない | 引数がない |
という意味であるため,int main(int argc,char
*argv[])のように,コマンドラインにて引数を
与えるつもりがない場合,int main(void)と書いた方が分かりやすいと言えますが,int
main()
でも文法(規格)上は何の問題もありません.
従って,厳密には, void main()やvoid main(void)では終了コードが返せないため,プログラム
終了したのか,それがOSには分からなくなってしまいます.これを厳密に回避するには,
C言語 | void main() { exit(0); } |
C++言語 | void main(void) { exit(0); } |
のように記述すれば,main関数の末尾で[強制終了]の上,正常終了である[終了コード0]を
システムに伝えるという処理を行うことが出来ますが,強制終了という意味では穏やかでは
ないのです.
main()の場合,厳密には文法ミスですが,コンパイラの方で足りない分を適当に補って何事も
ないコードにしておいてくれると考えた方が良さそうです.
結論としては,以下のいずれかで記述した方がよいと言えます.
コマンドラインでmain関数に引数を与えない | int main()またはint main(void) |
コマンドラインでmain関数に引数を与える | int main(int argc,char *argv[]) |
話を戻しましょう.コマンドラインで,引数を受け取るには,以下のように記述します,
int main(int argc,char *argv[])
引数名がargcやargvである必要はありませんが,殆どの解説書でこれらの名前が充てられて
いるので,慣例に従って説明します.
先ほどの例のようにタイプしたとします.
c:\>sample.exe 1.52 6.44 9.81 |
実行ファイル名の後,1.52 6.44 9.81という3つの変数が記述されています.上記のようにmain
関数に記述しておけば,以下のように認識されます.
argc | 引数の数 → 配列数 | 3 |
argv[] | 引数の配列 → 各引数の中身 但し,文字列として認識される |
1.52 6.44 9.81 |
サンプルプログラムを見て下さい.
#include <stdio.h> int main(int argc,char *argv[]){ int i; for(i=0;i<argc;i++){ printf("argv[%d] : %s\n",i, argv[i]); } return 0; } |
実行結果
argv[0] : c:\sample.exe argv[1] : 1.52 argv[2] : 6.44 argv[3] : 9.8 |
0番目の文字列で実行ファイル(フルパス) 1番目の数値の文字列 2番目の数値の文字列 3番目の数値の文字列 |
上記の通りですが,ちょっと扱いにくい点がありますので考えてみましょう.
コマンドラインにタイプされたものはすべて文字列として扱われ,スペースを区切りとして,それ
ぞれ長さの異なる複数の文字列として扱われます.しかも,それぞれの文字列は配列のポインタ
として扱われるため,アクセスの仕方を間違えると,本当に必要な引数が獲得できない可能性が
あるのです.
そこで,以下のように用意されている関数を用いて文字列配列の各要素を浮動小数点に変換
します.
文字列はそれ自体が配列であるため,(double)といったキャストを行うことができないのです.
#include <stdio.h> #include <stdlib.h> int main(int argc,char *argv[]){ int i; char *ep=NULL; for(i=1;i<argc;i++){ printf("argv[%d] : %lf\n",i, strtod(argv[i],ep)); } return 0; } |
strtod関数を利用するために必要なヘッダファイル strtod関数を利用するために必要な変数ポインタ 文字列を数値に変換する関数 |
なお,文字列配列の0番目は,実行ファイルのフルパスが格納されますので,無視して数値の配列に
格納された値は以下のものとなります.
argv[1] : 1.52 argv[2] : 6.44 argv[3] : 9.81 |
従って,これまでプログラム本文中で記述したり,scanfで取得していた数値は,プログラム実行時に
まとめて指定することが可能となります.
コマンドライン引数を利用するメリット
ソースファイル内の数値を変更してコンパイルすれば,もちろん必要な演算を行うことはできるのは確か
です.しかし,コンパイルしなおすのは時間が掛かり過ぎであるだけでなく,ソースファイルの他の部分を
うっかり変更してしまう危険性があるので,一度生成させた実行ファイルを変えることなく,必要な変数の
値のみを与える方法は有効なのです.
注意すべき点
実行ファイル名 変数 変数・・・のように記述するため,必要な値がプログラム内の必要な変数に格納
されたかどうか分からない危険性があります.従って,獲得されたコマンドライン引数を表示するような
工夫が必要となります.
※ 慣例的ですが,実行ファイル名 /?や実行ファイル名
/hと入力すれば,何番目にどのような値を入力
する必要があるか説明が表示できるようにプログラムを作成する方法もあります.
(参考) コマンドライン引数を用いない方法
コマンドライン引数が便利な場合もあれば,毎度引数を入力する必要があるため煩わしい場合もあります.
コンパイルを繰り返さず,複数の引数を扱うために,別途決められた名前のテキストファイルを作成しておき
これを読み込ませる方法もあります.例えば,sim.txtとかsim.iniのような名前をつけたりすればよいのです.
※ コマンドライン引数にファイル名を指定するという方法もあります.
複数の変数をプログラムで扱う工夫についてまとめ
方法 | メリット | デメリット |
対話的に変数を入力 | 1変数ごとに確認しながら 入力できる |
変数の数が多い場合面倒であり, 入力ミスを招く可能性がある. |
コマンドライン引数 | 一括して変数を入力でき, 軽快な操作となる. |
条件を変えたときは,全変数を 入力しなおさなければならない. |
テキストファイルの読み込み | 計算条件を予め検討して 用意しておくことができる. |
テキストエディタで編集の必要があり, スペース,タブ,改行コードでエラーを起こす. |