Cプログラミング入門

第20回Appendix 1 コマンドラインの引数

main()の引数

本連載では、main()関数は引数無しで使用していますが、本来は、

int main(int argc, char *argv[])

のように引数が付けられて呼び出されます。main()の引数の中には、このプログラム自体が起動された時にコマンドライン上で付けられた引数が格納されています。

int argc ← コマンドライン上の引数の個数
char *argv[] ← コマンドライン上の引数の文字列の配列

リストA1.1のall_args.cは、コマンドライン上の引数をすべて表示するプログラムです。図A1.1の実行例のように、⁠./all_args」に適当な引数を付けて実行すると、これらの引数がすべて順に表示されます。なお、コマンド名である「./all_args」も、ゼロ番目の引数としてargv[0]に入ります。

リストA1.1 all_args.c
#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;
}
図A1.1 リストA1.1(all_args.c)の実行例
$ gcc -O2 -o all_args all_args.c
$ ./all_args
argv[0] = ./all_args
$
$ ./all_args -o outfile -i infile
argv[0] = ./all_args
argv[1] = -o
argv[2] = outfile
argv[3] = -i
argv[4] = infile
$

さらにUNIX環境では*argv[]のあとに*envp[]という引数が付けられて、

int main(int argc, char *argv[], *envp[])

という形でmain()関数が呼び出されます。この*envp[]の中には、このプログラム自体の実行時の環境変数が格納されています。

環境変数をすべて表示するプログラムの例をリストA1.2に示します。図A1.2の実行例のようにall_envs.cを実行すると、envp[0]から順に環境変数が表示されます。

なお、*envp[]には、argcに相当するような環境変数全体の個数を格納した変数がありません。*envp[]は、最後の環境変数の次はNULLで終了するため、これを判断してfor文で繰り返し処理を行っています。

リストA1.2 all_envs.c
#include <stdio.h>

int
main(int argc, char *argv[], char *envp[])
{
  int i;

  for (i = 0; envp[i] != NULL; i++) {
    printf("envp[%d] = %s\n", i, envp[i]);
  }
  return 0;
}
図A1.2 リストA1.2(all_envs.c)の実行例
$ gcc -O2 -o all_envs all_envs.c
$ ./all_envs
envp[0] = CC=gcc
envp[1] = CFLAGS=-O2
envp[2] = DISPLAY=:0.0
envp[3] = HOME=/home/yamamori
envp[4] = LANG=ja_JP.eucJP
… 省略 …
$

ファイル名を指定して開く

前回作成した簡易catコマンドのプログラムのmycat.cは、標準入力からの入力専用です。しかし、実際のcatコマンドは、cat < fileだけでなくcat fileとして、コマンド引数でファイルを指定することもできます。

mycat.cで、ファイルコマンド引数でも指定できるようにするには、リストA1.3のようにプログラム中で自分でファイルをオープンする関数を呼び出すようにします。C言語の標準ライブラリ関数を使ってファイルをオープンするには、通常は(FILE *)型の変数を宣言してfopen()を呼び出しますが、ここでは、すでにオープンしている標準入力のstdinを使って、freopen()でstdinを開き直すことで処理を簡略化しています。freopen()を使えば、そのあとはstdinが目的のファイルを指すようになり、getchar()を使ってそのファイルの内容を読むことができます。

なお、このようにプログラム自身でファイルをオープンする場合は、すでにオープンしている標準入力とは異なり、ファイルが存在しなかった場合などのエラー処理も自分で行う必要があります。mycat_freopen.cでは、freopen()がエラーになった場合には、perror()関数を用いてエラーメッセージを出力するようにしています。perror()を使えば、⁠ファイルが存在しない」などのシステムで用意されたエラーメッセージを簡単に出すことができます。

リストA1.3 mycat_freopen.c
#include <stdio.h>

int
main(int argc, char *argv[])
{
  int c;

  if (argc > 1) {
    if (freopen(argv[1], "r", stdin) == NULL) {
      perror(argv[1]);
      return 1;
    }
  }

  while ((c = getchar()) != EOF) {
    putchar(c);
  }
  return 0;
}

mycat_freopenの実行例を図A1.3に示します。このように、以前のmycatとは違ってコマンドライン上でのファイルの指定時に標準入力をリダイレクトする<を付ける必要がありません。もちろん、<を付けて標準入力から読み込むこともできます。

図A1.3 リストA1.3(mycat_freopen.c)の実行例
$ gcc -O2 -o mycat_freopen mycat_freopen.c
$ ./mycat_freopen mycat_freopen.c
#include <stdio.h>

int
main(int argc, char *argv[])
… 省略 …
$

mycat_freopenで、指定されたファイルが存在しなかった場合は図A1.4のようにエラーメッセージが出ます。このエラーメッセージはperror()によって出力されています。

図A1.4 mycat_freopenで入力ファイルが存在しなかった場合
$ ./mycat_freopen testfile.txt
testfile.txt: No such file or directory
$

さらにargv[]すべてのファイルついて次々にopenし、ファイル内容を結合して標準出力に出力するようにすると、本物のcatコマンドにより近くなるでしょう。

おすすめ記事

記事・ニュース一覧