閉じる

C言語のコマンドライン引数入門(mainのargc/argv)

コマンドライン引数は、プログラムの動作を実行時に切り替える最も基本的な方法です。

本記事では、C言語のmain関数が受け取るargcargvを中心に、書き方、使い方、実行方法、そして初心者がつまずきやすい注意点まで、ていねいに解説します。

C言語のコマンドライン引数とは

コマンドライン引数の役割

プログラムは、実行時に引数を受け取ることで挙動を柔軟に変えられます。

たとえば、入力ファイル名、動作モード、数値パラメータなどをコマンドラインから渡せば、同じプログラムでも用途に応じて使い分けることができます。

コンパイルし直さずに動作を変更できるのが大きな利点です。

argcとargvの意味

C言語ではmainを次の形で宣言すると、実行時の引数を受け取れます。

argcは引数の個数、argvは引数の文字列配列です。

以下の表で概要を整理します。

項目役割
argcint引数の個数3なら、argv[0], argv[1], argv[2]が有効
argvchar*[] または char**引数文字列へのポインタ配列各要素はヌル終端文字列
argv[argc]char*ヌルポインタ(nullptr)番兵。文字列ではないので参照しない

配列の範囲は0からargc-1までです。

番兵としてargv[argc]はヌルポインタですが、ここを「最後の文字列」として参照してはいけません。

argv[0]は実行ファイル名

argv[0]は通常、実行ファイル名や起動に使ったパスを指します。

環境によってはフルパス、相対パス、あるいはシンボリックリンク名やラッパースクリプト名が入ることがあります。

必ずしも純粋なファイル名とは限らない点に注意します。

引数は文字列として渡る

コマンドライン引数はすべて文字列として渡されます。

数値として扱いたい場合はstrtolatoiで変換します。

初心者のうちはエラー検出ができるstrtolを推奨します。

atoiは失敗時の判定ができず、安全性に欠けます。

mainの書き方と使い方

基本の宣言(int main(int argc, char* argv[]))

コマンドライン引数を受け取るmainの代表的な宣言は次のとおりです。

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

どちらも意味は同じです。

引数を受け取らない形としてint main(void)も存在しますが、本記事のテーマでは前者を用います。

argvの参照方法

argvは「文字列へのポインタ」の配列です。

argv[i]i番目の引数の先頭アドレスを指し、そこにヌル終端文字列が置かれています。

通常、argv[0]はプログラム名、argv[1]以降がユーザが指定した引数です。

ループで走査すると全体を確認できます。

引数の個数チェック

アクセス前に必ず個数を確認します。

たとえば、2個の引数を必要とする場合はargcが期待値以上かチェックし、不足なら使い方を表示して終了します。

これにより範囲外アクセスを防げます。

サンプル

以下は、受け取った引数をすべて表示する簡単なプログラムです。

C言語
// ファイル名: echoargs.c
// 目的: 受け取ったコマンドライン引数を一覧表示する
// コンパイル例(GCC/Clang): gcc -o echoargs echoargs.c
// コンパイル例(MSVC): cl /EHsc echoargs.c

#include <stdio.h>

int main(int argc, char* argv[]) {
    printf("argc = %d\n", argc);

    // iは0からargc-1まで。argv[argc]はヌルポインタ(番兵)なので参照しない
    for (int i = 0; i < argc; ++i) {
        // %dでインデックス、%sで文字列を表示
        printf("argv[%d] = \"%s\"\n", i, argv[i]);
    }

    return 0; // 正常終了
}
実行結果
$ ./echoargs apple 123 "hello world"
argc = 4
argv[0] = "./echoargs"
argv[1] = "apple"
argv[2] = "123"
argv[3] = "hello world"

次は、2つの整数を受け取り、その合計を表示する例です。

文字列から数値への変換にstrtolを用いてエラーを検出します。

C言語
// ファイル名: add.c
// 目的: 2つの整数引数を受け取り、合計を表示する
// 使い方: ./add 12 30  (結果: 42)
// コンパイル例(GCC/Clang): gcc -o add add.c
// コンパイル例(MSVC): cl /EHsc add.c

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

long parse_long(const char* s, int* ok) {
    // strtolで10進として解釈
    errno = 0;
    char* end = NULL;
    long v = strtol(s, &end, 10);

    // 1) 変換できなかった(先頭から数字がない)
    // 2) オーバーフロー/アンダーフロー
    // 3) 末尾に不正文字が残った
    if (s == end) {
        *ok = 0;
    } else if (errno == ERANGE || v > LONG_MAX || v < LONG_MIN) {
        *ok = 0;
    } else if (*end != '
// ファイル名: add.c
// 目的: 2つの整数引数を受け取り、合計を表示する
// 使い方: ./add 12 30  (結果: 42)
// コンパイル例(GCC/Clang): gcc -o add add.c
// コンパイル例(MSVC): cl /EHsc add.c
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <limits.h>
long parse_long(const char* s, int* ok) {
// strtolで10進として解釈
errno = 0;
char* end = NULL;
long v = strtol(s, &end, 10);
// 1) 変換できなかった(先頭から数字がない)
// 2) オーバーフロー/アンダーフロー
// 3) 末尾に不正文字が残った
if (s == end) {
*ok = 0;
} else if (errno == ERANGE || v > LONG_MAX || v < LONG_MIN) {
*ok = 0;
} else if (*end != '\0') {
*ok = 0;
} else {
*ok = 1;
}
return v;
}
int main(int argc, char* argv[]) {
if (argc != 3) {
// 期待する引数個数は2(プログラム名を含めるとargcは3)
fprintf(stderr, "使い方: %s <整数A> <整数B>\n", argv[0]);
return 1; // 異常終了
}
int ok1 = 0, ok2 = 0;
long a = parse_long(argv[1], &ok1);
long b = parse_long(argv[2], &ok2);
if (!ok1 || !ok2) {
fprintf(stderr, "エラー: 整数に変換できない引数があります。\n");
return 1;
}
long sum = a + b;
printf("%ld\n", sum);
return 0;
}
') { *ok = 0; } else { *ok = 1; } return v; } int main(int argc, char* argv[]) { if (argc != 3) { // 期待する引数個数は2(プログラム名を含めるとargcは3) fprintf(stderr, "使い方: %s <整数A> <整数B>\n", argv[0]); return 1; // 異常終了 } int ok1 = 0, ok2 = 0; long a = parse_long(argv[1], &ok1); long b = parse_long(argv[2], &ok2); if (!ok1 || !ok2) { fprintf(stderr, "エラー: 整数に変換できない引数があります。\n"); return 1; } long sum = a + b; printf("%ld\n", sum); return 0; }
実行結果
$ ./add 12 30
42

$ ./add 12 abc
エラー: 整数に変換できない引数があります。

char* argv[] と char** argv の違い

関数パラメータとしてはどちらも同等です。

配列パラメータchar* argv[]は関数宣言上char** argvに調整されます。

可読性の観点で、argvが「文字列へのポインタの配列」であることを示したいならchar* argv[]を、よりポインタ寄りに捉えたいならchar** argvを使います。

次の表は違いをまとめたものです。

宣言意味合い実際の呼び出し時の型
char* argv[]文字列へのポインタの配列という意図を表しやすい関数内ではchar**に調整される
char** argv二重ポインタであることを明示そのままchar**

どちらを選んでも動作は同じで、コードスタイルの問題です。

実行方法と確認手順

コンパイル手順

代表的なコンパイラでのコンパイル例を示します。

GCCまたはClang(Linux/macOS)
gcc -o echoargs echoargs.c
gcc -o add add.c

MinGW-w64(GCC for Windows)
gcc -o echoargs.exe echoargs.c
gcc -o add.exe add.c

MSVC(Developer Command Prompt)
cl /EHsc echoargs.c
cl /EHsc add.c

コンパイル後、シェルで実行します。

Unix系シェル(bashやzsh)では次のように実行します。

実行結果
./echoargs apple 123 "hello world"
./add 12 30

WindowsのPowerShellやコマンドプロンプトでは次のように実行します。

実行結果
.\echoargs.exe apple 123 "hello world"
.\add.exe 12 30

スペースを含む引数

空白で引数が区切られるかどうかは「シェルのルール」に従います

文字列にスペースを含めたい場合は引用符で囲むか、エスケープします。

Shellbash/zsh
./echoargs "hello world" path\ with\ spaces
PowerShellPowerShell
.\echoargs.exe "hello world" 'path with spaces'
Batch Filecmd.exe
.\echoargs.exe "hello world" path^ with^ spaces

どのシェルを使っているかで引用やエスケープの書き方が変わるため、実行環境を意識して入力してください。

IDEでの設定

IDEを使う場合、プロジェクト設定で「コマンドライン引数」を指定できます。

代表例を挙げます。

  • Visual Studio: プロジェクトのプロパティ → 構成プロパティ → デバッグ → コマンド引数
  • Xcode: SchemeのEdit → Arguments → Arguments Passed On Launch
  • CLion: Run/Debug Configurations → Program arguments
  • VS Code: tasks.jsonやlaunch.jsonのargsに配列で指定

GUI上であらかじめ引数を登録しておけば、毎回同じ引数で素早くテストできます。

よくあるミスと注意点

argc未チェックのアクセス

もっとも多い不具合は、argcを確認せずにargv[1]などへアクセスすることです。

引数が不足していると未定義動作になります。

最初にargcのチェックを行う習慣をつけましょう。

添字の取り違え

argv[argc]はヌルポインタであり、実データの終端を示す番兵です。

ここを%sで出力しようとするとクラッシュの原因になります。

必ずi < argcという条件でループしましょう。

argvを勝手に書き換えない

環境によってはargv[i]が指す文字列を変更できる場合もありますが、初心者は読み取り専用と考えるのが安全です。

特にargv[i]が文字列リテラルや読み取り専用領域を指す可能性がある実装では、書き換えが未定義動作になります。

空白の扱いはシェルのルール

引数の分割や展開はシェルが行い、C言語側では「結果の文字列」を受け取るだけです。

ワイルドカードの展開やクォートの挙動はシェルによって異なり、プログラムからは制御できません。

動作が合わないときは、実行しているシェルとそのクォート規則を確認してください。

まとめ

本記事では、C言語のmainが受け取るargcargvについて、役割、宣言、参照方法、引数チェック、実行方法、そして注意点を体系的に解説しました。

引数はすべて文字列で渡されるため、必要に応じてstrtolなどで安全に変換し、アクセス前にargcを必ず確認するのが基本です。

また、スペースやクォートの扱いはシェルのルールである点も忘れないでください。

これらの基礎が身につけば、設定ファイルなしでも柔軟に動作を切り替えられる、小さくて使いやすいプログラムを書く力が身につきます。

この記事を書いた人
エーテリア編集部
エーテリア編集部

プログラミングの基礎をしっかり学びたい方向けに、C言語の基本文法から解説しています。ポインタやメモリ管理も少しずつ理解できるよう工夫しています。

クラウドSSLサイトシールは安心の証です。

URLをコピーしました!