プログラミング演習1
― 課題4の付録2 ―
【資料】
課題4の付録2(pdf)
コマンド行の引数
→ カーニハン、リッチー 「プログラミング言語C」 第5章 5.10 (pp.139〜140) 参照Windowsのコマンドプロンプト(DOSプロンプト)やUNIXのコマンドシェルでは プログラム実行時に直接パラメータを引き渡す方法が用意されている。 例えばCで作られた大多数のDOSコマンドやUNIXコマンドは、実行時のパラメータにより 機能を切り替えられるようになっている。
プログラムに汎用性を持たせる段階になると、初心者は入力促進させてパラメータや数値を入力させる 「対話的なプログラム」を作りがちだが、実はこれは人間が自らコンピュータにこき使われる状況を 作り出しているといえる。 最初にパラメータを用いて内容を指示したあと、延々と実行させてほっておき、 仕事が終わったら知らせるといった「バッチ処理」こそ、コンピュータにこき使われずに 人間が楽できる本来の使い方である。 そのうまみを享受するためには、汎用性のあるプログラムにコマンド行の引数を渡す方法を 早めにマスターするのがよい。 main関数の引数として以下のように書くと、コマンド行の引数が利用できるようになる。int main(int argc, char *argv[])整数変数 argc (argument countの意味) にはコマンド行の引数の個数が入る。 文字列配列ポインタ argv (argument vectorの意味) にはコマンド行の引数の内容が格納される。 最初の文字列 argv[0] には起動したプログラムのコマンド名が入り、 これも argc の数に含まれる。 2つめ以降の argv[1], argv[2],... にはコマンドに続く引数が、 スペースによって区切られて、文字列として順に格納される。 よって、以下のプログラム(mainarg.c)#include <stdio.h> int main(int argc, char *argv[]) { int i; for (i = 1; i < argc; i++) printf("%s ", argv[i]); printf("\n"); return 0; }を次のように実行すれば、コマンド行の引数が 実際にどのように引き渡されたかを確認できる。Z:\proen1\kadai4>mainarg 1.0 234 abc !"# 1.0 234 abc !#ただし、数値を引数にしたつもりでも文字列として引き渡されるので、 数値を変数に代入する際には数値変換関数(atoi(), atol(), atof())を用いて 変換する必要がある。 例えば実数を3つ入力したい場合は、以下のようにすればよい(mainarg3.c)。
#include <stdio.h> // printf #include <stdlib.h> // atof int main(int argc, char *argv[]) { double x1, x2, eps; if (argc < 4) { printf("usage: %s x1 x2 eps\n", argv[0]); return 1; } x1 =atof(argv[1]); x2 =atof(argv[2]); eps=atof(argv[3]); printf("[% g, % g] % e\n", x1, x2, eps); return 0; }実行例Z:\proen1\kadai4>mainarg3 1 2.0 1e-6 [ 1, 2] 1.000000e-006argc の数にはコマンド名も含まれるため、引数の個数よりも1つ多いことに注意。
2次元配列の引き渡し
→ 熊谷・玉城・白川「例題で学ぶC言語」第12章 12.2〜12.3 (pp.110-114) 参照
→ 柴田望洋「新版 明解C言語 入門編」第6章 6-2 (p.138) 参照配列を関数(サブルーチン)とやりとりする場合、 受け取る側では主に2つのいくつかのやりかたがある。
初心者のうちは(1)の方法しか知らなくてもやむを得ないが、 プログラムが大きくなると大域変数の管理が大変になるので、 (2)のやり方のほうがより一般的で、エレガントである。
- (1)
- 大域変数でやり取りする。
- (2)
- 関数(サブルーチン)の引数を介してやり取りする。
引数を介するやりかたにおいては、いくつかの書き方が許される。2次元以上の配列では2つめの方法は要注意である。
- 配列の大きさ(サイズ)を明記する。
int func(double x[3], double f[3]) { ……………… }大きさを事前に定数式として定義しておくほうが便利なので、実際には#define ND 3 int func(double x[ND], double f[ND]) { ……………… }- (最上位の)配列の大きさを省略する。
int func(double x[], double f[]) { ……………… }int Jcalc(double x[], double J[][]) { ……………… }では、エラーが出てしまう。int Jcalc(double x[], double J[][ND]) { ……………… }としなければならない。これは、引き渡された2次元配列が どこで折り返されているかという最低限のサイズ情報がないと、 配列の要素を特定できないからである。 省略できるのは最上位(一番左の[])の大きさのみである。
2次元情報を1次元配列に並べ替えておくといった安易な方法もある。int Jcalc(double x[], double J[]) { ……………… J[1] = …; // J11 J[2] = …; // J12 J[3] = …; // J21 J[4] = …; // J22 }
【目次】 | 【1.】 | 【2.】 | 【3.】 | 【付録1】 |