ポインタ虎の巻

ダブルポインタ **argv の使い方

このような多重配列を使った機構はC言語プログラムで多用される。典型的な例がコマンドライン引数を取得するための argc, argv 機構である。プログラムを実行する際に、

% ls -l -F -a /usr /usr/lib 

のようにコマンドラインで起動する。この時、ls プログラムとしては、コマンドラインで指定された引数をプログラム内部で取得する必要がある。このための機構として、argc, argv 機構が用意されている。

典型的なC言語のmain関数の定義は以下である。

int main( int argc, char **argv )
{ 
}

この時、main関数の2つの引数を argc, argv という名前で呼ぶのが常識となっている。(argc = argment count, argv = argment variable)

この機構は多次元配列の応用である。つまり、argv は、文字列の開始アドレスを示す10個の char * の配列を指しているポインタである。そして、最初の文字列の開始アドレスを示す argv[0] は最初の文字列へのポインタであり、*argv[0] は、最初の文字列の最初の文字を示す。ということは、**argv も最初の文字列の最初の文字を示しているのである。

そして、コマンドライン引数の数が5個の場合は、argv[5] == NULL となり、コマンドライン引数の終りを示す。つまり、コマンドライン引数の数の終りを示すためにNULLポインタが使われている。

だから典型的なコマンドライン引数処理は以下のようになる。argv[0] にはコマンド名自体("ls")が入っており、通常の処理では関心がないことに注意。

int main( int argc, char **argv )
{ 
        while( *++argv != NULL ){ 
                if( **argv == '-' ){
                        switch( *(*argv+1) ){
                        case 'l':  /* -l オプション処理 */
                                .........
                        }
                } else {
                        break;
                }
        }
        while( *argv != NULL ){
                現在、*argv は処理対象となるファイル名を示し
                ている。それらが次々と処理されていく。
                argv++;
        }
}

最初のwhileループでは、まずポインタをインクリメントしてから処理しており、後のwhileループでは処理してからインクリメントしている。これは、第0引数はコマンド名であり、この場合は関心がないために、argv[0]の処理を飛ばしているのである。しかし、argv[4] がオプション文字列ではない(`-'で始まらない)時には、break文によって最初のループを抜けて、2番目のwhileループに入る。オプション文字列ではないということは、それが処理すべきファイル名であることだから、この時にはあらかじめポインタをインクリメントすればそのファイル名の処理が飛んでしまう。だから、処理が終ってから、argv をインクリメントする。

あと、やや判りにくいのは switch( *(*argv+1) )である。これは冷静に考えればいいだけである。

  1. argv は現在処理すべき文字列へのポインタである。
  2. *argv は現在処理すべき文字列(文字へのポインタ)である。
  3. **argv は現在処理すべき文字列の最初の文字である。
  4. *argv + 1 は現在処理すべき文字列の2字目に対するポインタである。&argv[0][1] と同じである。
  5. だから現在処理すべき文字列の2字目は、*(*argv+1)である。

このように考えていけば、argv だけを扱っても正しく処理を行っていける。argc は使っても使わなくてもよいが、一般には使うことが多い。

このようにダブル・ポインタを使った文字列配列の処理は、C言語では頻繁に現われるので、是非この機会に馴れておくことが望ましい。

課題

  1. 適当なコマンドの引数処理を考えて、実際にargc,argvを使って処理をしてみること。処理に馴れるまで繰り返し行うこと。


copyright by K.Sugiura, 1996-2006