C言語入門|コマンドライン引数を受け取る

それじゃ、いよいよこの章の締めくくりだ。
バトルRPGを作るのにとても便利な、もう1つの main 関数の書き方 を紹介しよう。

「main関数って、ずっと同じ形で書いてきましたよね?」

これまで私たちは、次のような形で main 関数を書いてきました。

int main(void)
{
    :
}

しかし、C言語の仕様では、次のような宣言も正式に認められています。

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

「argc? argv? しかも char** ……なんだか急に難しそうですね。」

大丈夫。
ここまで 文字列・配列・ポインタ を理解してきたなら、
この形はむしろ「自然な帰結」だと感じられるはずです。

コマンドライン引数とは何か

プログラムは、起動するときに
スペースで区切った複数の文字列 を渡すことができます。

このとき渡される文字列を
コマンドライン引数(command line argument)
と呼びます。

たとえば、バトルRPGのプログラム rpg があったとしましょう。

通常は、起動後に入力を求める形になります。

バトルRPG
プレイヤー名を決めてください:アキラ
初期HPを決めてください:1000
アキラ(HP=1000)でゲームを開始します!

しかし、起動と同時に初期値を指定できたら、もっと便利です。

「rpg アキラ 1000」と初期値を指定して起動

バトルRPG
アキラ(HP=1000)でゲームを開始します!

このとき、

  • rpg
  • アキラ
  • 1000

という 3つの文字列 が、
プログラム起動と同時に main 関数へ渡されます。

main関数が特別な理由

通常の関数は、
「どこから呼び出されるか」
を考えて引数を設計します。

しかし main 関数は特別です。

main 関数は
OSから直接呼び出される関数
であり、プログラムの入口そのものです。

そのため、

  • プログラム名
  • 起動時に指定された引数

といった情報が、
最初から main 関数の引数として渡される
という仕組みになっています。

argc と argv の意味

int main(int argc, char** argv)

この2つの引数には、明確な役割があります。

名前意味
argc引数の個数(argument count)
argv引数の配列(argument vector)

argv は「文字列の配列」

ここが、これまで学んできた内容と直結する重要ポイントです。

argv は char** 型ですが、
これは

char* の配列

を意味します。

つまり argv は、

添字内容
argv[0]プログラム名(が格納されている先頭アドレス)
argv[1]第1引数(が格納されている先頭アドレス)
argv[2]第2引数(が格納されている先頭アドレス)

という 文字列の配列 です。

すべての要素は
ヌル終端されたC文字列の先頭アドレス
になっています。

argc は配列の要素数

argc には、
argv に入っている要素数が格納されています。

rpg アキラ 1000

この場合、

変数
argc3
argv[0]"rpg"
argv[1]"アキラ"
argv[2]"1000"

となります。

argv は配列ですが、
何個あるかは argc を見なければわかりません。

この2つは必ずセットで使います。

サンプルプログラム

プロジェクト名:11-12-1 ソースファイル名: sample11-12-1.c

#include <stdio.h>
#include <stdlib.h>

int main(int argc, char** argv)
{
    if (argc < 3) {
        printf("使い方: rpg 名前 初期HP\n");
        return 1;
    }

    char* name = argv[1];
    int hp = atoi(argv[2]);

    printf("%s(HP=%d)でゲームを開始します!\n", name, hp);
    return 0;
}

argv に入っているのは すべて文字列 です。
そのため、数値として使いたい場合は atoi などで変換します。

Visual Studioでの実行方法(重要)

「でも、Visual Studioってコマンドラインから起動しないですよね?」

その通りです。
Visual Studio では、実行時にコマンドライン引数を設定する 必要があります。

Visual Studioでの手順

  1. メニューから
    プロジェクト → プロパティ を選択する
  2. 左側のツリーで
    構成プロパティ → デバッグ を選択する
  3. 「コマンド引数」という項目を探す
  4. そこに次のように入力する
    アキラ 1000
  5. 設定を保存し、
    デバッグ → デバッグの開始 を選択して実行する

すると、main 関数は次の状態で開始されます。

  • argc は 3
  • argv[1] は "アキラ"
  • argv[2] は "1000"

なぜ char** なのか(整理)

ここで char** の正体を整理しておきましょう。

意味
char1文字
char*文字列
char**文字列の配列

argv は
複数の文字列をまとめて扱うための配列
なので char** 型になるのです。

コマンドライン引数の使いどころ

コマンドライン引数は、

  • 入力待ちをせず
  • 起動と同時に
  • 文字列として情報を受け取れる

という特徴があります。

初期設定、モード切り替え、テスト用パラメータなどに使うと、
とてもスマートなプログラムになります。

まとめ

ここまでで、

  • 文字列は先頭アドレスで扱う。
  • 文字列は配列として並べられる。
  • main 関数は文字列配列を受け取れる。

という 文字列文化の集大成 に到達しました。

argc と argv は、
C言語における「文字列 × 配列 × ポインタ」の完成形です。

ここまで理解できていれば、
もう 文字列で困る場面は激減 します。