C++入門/コマンドライン引数

-,東京都立大学,情報科学科
戻る

コマンドライン引数について説明する.Bash でコンパイルしたプログラムを実行するための知識があることを前提とする.この方法を学べば,プログラムを起動するときに,処理するべきファイルのパスなどを指定することができるようになる.

これは規約であるため,特に仕組みと言ったものを気にする必要はなく,次に示す例を覚えて貰えれば十分である.例えば,のプログラム excmd.cpp をコンパイルして,a.out があるとする.コンパイルのためのコマンドは以下のとおりである.

g++ excmd.cpp
#include <iostream>
int main(int argc, char** argv){
    for(int i=0;i<argc;++i){
        std::cout << argv[i] << "\n";
    }
    return 0;
}
excmd.cpp のソースコード

このとき,以下のコマンド

./a.out arg1 arg2

を実行すると次の通り出力されるはずである.

./a.out
arg1
arg2

このコード excmd.cpp の関数 main には二つの引数が記載されている.それらはそれぞれ,int 型の argc, char** 型の argv となっている.C++ の規約で,このように main を定義すると,プログラム起動時に渡された文字列を空白で区切った文字列の配列が argv に,その文字列の数が argc に渡されることとなっている.文字列自体は 「文字列」で解説したとおり配列にっているため,文字列を受け取るためには配列同様ポインタを受け取る必要がある.さらに,その文字列(配列)の配列を受け取るために,char* のポインタである char** を受け取ることになっている.ややこしいが,こういう決まりなので覚えていただきたい.私はこういった二重ポインタが必要な実装は良くないと思うが,規約なので覚えなくてはならない.

先程述べたプログラム起動時に渡された文字列,であるが,プログラムを起動するために必ずプログラム名を指定する必要があるため,argc は 0 になることはない.このことは,先ほどの出力に ./a.out が含まれていることからもわかる.この決まりにより,プログラムがどのように呼び出されたかを知ることができる.呼び出され方により処理を変えたい場合は argv の第一文字列を参考にすると良い.

argv の第2文字列以降は,プログラム名以降に渡された引数が入る.繰り返しになるが,例えば以下,

./a.out example

では argv に ./a.out, example の二つの文字列が入り,argc は 2 となる.文字列は空白で区切られると覚えておこう.空白を含む文字列を分割されないように渡したい場合は以下の通り,""で当該のものを囲い起動する.

./a.out example "this is a string including space"

上記の出力は次のとおりになるはずである.

./a.out
example
this is a string including space

以上参考にされたい.また,実はこのコマンドライン引数の受け渡しの決まりは,C++ 以外でもほぼ同じである.ここでは C++ での読み出し方を説明したが,他の言語を使う際も同様のことが可能であることを思い出してもらいたい.

パラメータを受け取る実装の例

ほとんどの場合以下の実装で事足りるであろう.以下は6から10行目にある変数n, a, t, c, mvにコマンドライン引数により値を指定する例である.連想配列などを用いてより高速に描くこともできるが,普通はここに速度が必要ないので,この書き方で十分である.ポインタなど凝った書き方も考えられるが,以下の書き方は面倒ではなく一般性も高いため,このように条件文でポインタなど使わずにかくことをおすすめする.

#include <iostream>
#include <vector>
#include <string>
using namespace std;
int main(int argc, char** argv){
    int n;
    double a;
    int64_t t;
    string c;
    vector<double> mv;
    string cmd="";
    for(int i=1;i<argc;++i){
        string s = argv[i];
        if(cmd == ""){
            cmd = s;
            continue;
        }

        if     (cmd == "--n"){n = stoi(s);}
        else if(cmd == "--a"){a = stod(s);}
        else if(cmd == "--t"){t = stoi(s);}
        else if(cmd == "--c"){c = s;}
        else if(cmd == "--v"){mv.push_back(stod(s));}

        cmd = "";
    }
    cout << "n: " << n << "\n";
    cout << "a: " << a << "\n";
    cout << "t: " << t << "\n";
    cout << "c: " << c << "\n";
    for(int i=0;i<mv.size();++i){
       cout << "mv["<<i<<"]: "  << mv[i] << "\n";
    }

    return 0;
}
コマンドライン引数のコードの例

実行すると次のとおりである.コンパイルコマンドも示してある.$の行はコマンドを示し,$のない行は標準出力を示す.

$ g++ command-line2.cpp -std=c++20
$ ./a.out --n 1 --a 2.2333121 --v 1 --v 1 --v 2.2 --v -3.54554 --v -4  --c "this is a test"
n: 1
a: 2.23331
t: 140456642725208
c: this is a test
mv[0]: 1
mv[1]: 1
mv[2]: 2.2
mv[3]: -3.54554
mv[4]: -4