コマンドライン引数

main関数の引数

今までのプログラムでは、main関数の引数はすべて空でした。
実はmain関数にも引数を指定することができます。

#include <stdio.h>

int main(int argc, char *argv[])
{
    printf("引数の数: %d\n", argc);

    for (int i = 0; i < argc; i++)
    {
        printf("%d: %s\n", i, argv[i]);
    }
    getchar();
}

main関数の引数に注目してください。
int型の引数と、char*型の配列引数を受け取るようになっています。

main関数はプログラムの実行時に自動的に呼び出されるので、コード中でmain関数に引数を指定して呼び出すことはありません。
main関数の引数はプログラムの実行時にOS(Windowsとか)から渡されます。
これをコマンドライン引数といいます。

コマンドライン引数

例えばWindows上で何かのプログラムを起動する場合、普通はプログラムのアイコン(実行ファイル)を選択してEnterキー、またはマウスでダブルクリックして起動します。
この場合はほとんど意識されないのですが、プログラムによっては起動オプションというものがあります。

例えばメモ帳は、そのまま起動すれば中身が空の状態で起動します。
しかし、メモ帳のアイコンにテキストファイルをドラッグ&ドロップして開けば、そのテキストが開かれた状態で起動します。
メモ帳の通常起動
メモ帳のファイル指定起動

プログラム(実行ファイル)にファイルをドラッグ&ドロップすると、そのプログラムにドロップしたファイルのパスが渡されます。
パスを受け取ったプログラムは、そのファイルを自動で開くなどの処理を行います。

最近はあまり使用されませんが、コマンドプロンプトからプログラムを起動する場合には起動オプションはよく用いられていました。
コマンドプロンプトから起動オプションを指定して起動

プログラム名に続いて半角スペースを空け、ファイル名を指定するとそのファイルを読み込んだ状態でメモ帳が起動されます。
これはファイルをドロップするのと同じことです。

ただし、どのような値を受け取れるかはプログラムによって異なります。
メモ帳は、受け取ったファイルパスを自動的に開いた状態で起動するようにプログラムが作られているということになります。

長くなりましたが、外部から値を指定してプログラムを実行した時、その値を受け取る方法がコマンドライン引数であり、コマンドライン引数はmain関数の引数として受け取れるわけです。

int argc

main関数の第一引数argcは普通のint型変数(引数)です。
これは次の配列argvの要素数が格納されています。
Windowsでは最低でも1以上の値となるようです。

「arg」というのは「argument」の略で、まさに「引数」という意味です。
「argc」のcの意味はよくわかりませんが、おそらくcountか何かだと思います。

main関数であっても引数名は自由ですが、慣習的に「argc」と「argv」が用いられています。
(argvのvはたぶんvalueかvariableあたりの意味)

char *argv[]

第二引数の引数argvには、実際に受け取ったコマンドライン引数の文字列が配列で格納されています。
ポインタの配列なので、複数の文字列を同時に受け取れます。

Windowsではコマンドライン引数に何も指定しない場合、最初の要素には実行ファイル自身のフルパス名が格納されるようです。
そのため、最初のサンプルコードを実行すると実行ファイルの場所が表示されます。
コマンドライン引数のサンプルコードの実行結果

試しに、最初のサンプルコードをビルドして、実行ファイルに適当なファイルをドラッグ&ドロップして起動してみてください。
コードの実行結果に、ドロップしたファイル名が追加されているはずです。
(Visual Studioでビルドした実行ファイルは、プロジェクトファイルの保存場所の「Debug」フォルダ内にあります)
サンプルプログラムにファイルをドラッグ&ドロップした例

少し実用的なコード

以下に、コマンドライン引数を利用して、受け取ったファイル名の名前とファイルサイズを表示するコードのサンプルを示します。

#include <stdio.h>
#include <sys/stat.h>

int main(int argc, char *argv[])
{
    if (argc <= 1)
    {
        printf("コマンドライン引数が空です。\n");
        printf("Enterキーで終了");
        getchar();
        return 0;
    }

    struct stat statBuf;
    for (int i = 1; i < argc; i++)
    {
        if (stat(argv[i], &statBuf) == 0)
        {
            printf("%s\n", argv[i]);
            printf("ファイルサイズ: %d\n\n", statBuf.st_size);
        }
        else
        {
            printf("%sは存在しません。\n\n", argv[i]);
        }
    }
    printf("Enterキーで終了");
    getchar();
}

引数argcが1以下ならばコマンドライン引数に何も指定されていないことになりますので、プログラムを終了させます。

後はstat関数とstat構造体を利用して、ファイルが存在すればファイルサイズを表示します。
複数のファイルを同時にドラッグ&ドロップしてもすべて表示できます。
(stat関数、stat構造体に関してはファイルサイズの取得を参照)

外部から自由に値を受け取れるので、例えばfopenでファイルを開いてテキストを処理するプログラムにもできます。
受け取れるのはファイル名に限りませんから、特定の文字列を指定して起動した場合には動作を変更するプログラムにすることも可能です。
(起動オプション、起動スイッチ)

なお、ファイルパス以外の文字列をプログラムに渡すには、上述したコマンドプロンプトを使用する方法と、実行ファイルのショートカットを作成し、プロパティで引数を指定する方法があります。
ショートカットファイルでコマンド引数を指定する