0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

C言語のmain関数入門|int main(void)・argc・argv・void mainの違い

0
Last updated at Posted at 2026-06-26

C言語を基礎から順に学びたい場合は、C言語 学習ロードマップ を参照してください。

この記事は補足です。先にポインタ入門を読むと、char *argv[]の見方が分かりやすくなります。

C言語のプログラムには、基本的に main 関数があります。

これまでの例では、次の形を使ってきました。

int main(void)

ただ、C言語のコードを読むようになると、次のような書き方も見かけます。

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

また、古いコードや特定の開発環境では、次の書き方を見かけることがあります。

void main(void)

これらは何が違うのでしょうか。

この記事では、main 関数が担う役割、int main(void)int main(int argc, char *argv[]) の使い分け、そして void main を新しく書くべきではない理由を、順番に確認します。

この記事は、Windows 11 + WSL + GCC でC言語を学ぶことを前提にしています。

前提

この記事では、関数、文字列、配列、ポインタの基本を使います。

まだ読んでいない場合は、先に次の記事を読んでください。

この記事で分かること

  • main 関数がプログラムの入口になる理由
  • int main(void) の意味
  • return 0;return 1; の意味
  • void main を新しく書かない方がよい理由
  • argcargv の意味
  • コマンドライン引数を受け取り、使い方を表示する方法
  • 文字列で渡された引数を整数として安全寄りに扱う最初の方法

先に結論

普段のC言語学習では、次の2つを使い分ければ十分です。

// 起動時に値を受け取らないプログラム
int main(void)
// 起動時にターミナルから文字列を受け取るプログラム
int main(int argc, char *argv[])

void main(void) は、新しく書くコードでは使わないでください。

一部の処理系ではコンパイルや実行ができる場合がありますが、WSL + GCC で標準的なCとして学ぶなら、main の戻り値は int に統一します。

1. main 関数はプログラムの入口

C言語のプログラムは、基本的に main 関数から処理を始めます。

#include <stdio.h>

int main(void)
{
    printf("プログラムを開始します。\n");

    return 0;
}

実行すると、次の流れになります。

ターミナルから実行する
↓
C言語の実行環境がプログラムを起動する
↓
main 関数の先頭から処理が始まる
↓
return で main 関数が終わる
↓
プログラムが終了する

main は、ほかの関数と同じように見えます。

ただし、プログラムを起動した側から最初に呼ばれる特別な関数です。

main は自分で呼び出さない

通常の関数は、自分で呼び出します。

print_message();

一方、main は自分で呼び出しません。

// main(); のようには書きません。

ターミナルから実行したときに、実行環境が main 関数を呼び出します。

そのため、学習用のプログラムでは、処理の始まりを main 関数に書きます。

2. int main(void) の意味

これまで使ってきた形を、単語ごとに分けて見ます。

int main(void)
部分 意味
int main 関数が、終了時に整数を1つ返す
main プログラムの入口となる特別な関数名
void この関数は、呼び出されるときに値を受け取らない

つまり、次のように読めます。

値を受け取らずに始まり、
終了時に整数を返す main 関数

void は「何も返さない」ではない

int main(void)void は、main の戻り値を表しているわけではありません。

void は、かっこの中にあるため、引数を受け取らないことを表します。

int main(void)

一方、先頭の int は、終了時に整数を返すことを表します。

int main(void)

終了時に整数を返す

この2つは役割が違います。

見る場所 役割
main の前にある int 関数が返す値の型
main( ) の中にある void 関数が受け取る値がないこと

3. return 0; は何を返しているのか

main 関数の最後には、次のコードを書いています。

return 0;

これは、プログラムを起動した側へ、終了結果を返す処理です。

main 関数
↓
return 0;
↓
プログラムを起動した側へ 0 を返す
↓
正常に終わったことを伝える

一般的には、次のように扱います。

戻り値 意味
0 正常に終了した
0以外 途中で問題があり、正常には終了していない

たとえば、必要な入力がなかった場合は、return 1; として終了できます。

#include <stdio.h>

int main(void)
{
    printf("エラーが発生したため、処理を終了します。\n");

    return 1;
}

WSLで終了結果を確認する

WSLのターミナルでは、プログラムを実行した直後に次のコマンドを実行すると、直前のプログラムが返した値を確認できます。

./return_example
echo $?

return 0; のプログラムなら、次のように表示されます。

0

return 1; のプログラムなら、次のように表示されます。

1

最初のうちは、すべてのプログラムで終了結果を確認する必要はありません。

ただし、あとでシェルスクリプトや自動実行を扱うときは、終了結果が「次の処理を続けるか」を判断する材料になります。

return 0; は省略できるのか

現在のC言語では、main 関数の最後まで到達した場合、return 0; を書いた場合と同じように正常終了として扱われます。

そのため、次のコードも動作します。

#include <stdio.h>

int main(void)
{
    printf("Hello, World!\n");
}

ただし、このシリーズでは return 0; を書くことにします。

理由は、次の2つです。

プログラムがどこで終わるかを初学者が確認しやすい
↓
return 1; などの異常終了と並べて理解しやすい

4. int main() ではなく int main(void) と書く理由

次の2つは、見た目がよく似ています。

int main()
int main(void)

どちらも、main 関数の定義としては引数なしで書かれているように見え、GCCでも受け付けられます。

ただし、C言語では () を使う書き方は、引数の型を明示しない古い形式です。

特に、関数の宣言で次のように書いた場合は、「引数がない」ことを明確には表しません。

int process();

そのため、引数を受け取らないことを明確にしたい場合は、void を書きます。

int main(void)
書き方 学習用コードでの扱い
int main(void) 引数を受け取らないことが明確。これを使う
int main() 古い形式。新しく書くコードでは使わない

この書き方なら、コードを読む人にも、コンパイラにも「この関数は引数を受け取らない」と明確に伝わります。

5. void main(void) は何が違うのか

次のようなコードを見かけることがあります。

void main(void)
{
    /* 処理 */
}

void は「値を返さない」ことを表します。

そのため、void main(void) は、終了時にプログラムを起動した側へ終了結果を返せません。

int main(void)
↓
終了結果を整数で返せる

void main(void)
↓
終了結果を返す場所がない

WSL + GCCでは警告になる

この記事で使っているコンパイル方法で、次のコードを確認します。

#include <stdio.h>

void main(void)
{
    printf("Hello, World!\n");
}
gcc -std=c17 -Wall -Wextra -Wpedantic void_main.c -o void_main

GCCでは、次のような警告が出ます。

warning: return type of 'main' is not 'int'

警告が出ても実行できる場合はあります。

ただし、コンパイルできたことは、標準的で移植しやすい書き方であることを意味しません。

このシリーズでは、警告を残さないコードを書くため、void main は使いません。

では、void main は絶対に見ないのか

いいえ。古いコードや、特定の組み込み開発環境の資料などで見かけることはあります。

組み込み開発では、OSがある通常のアプリケーションとは異なり、プログラムの開始方法や終了の考え方が、処理系やプロジェクトのルールで決められている場合があります。

そのようなプロジェクトでは、顧客・製品・コンパイラのルールを優先します。

ただし、新しくC言語を書くとき、特にWSL + GCCで学習するときは、次の形に統一してください。

int main(void)

または、コマンドライン引数を受け取る場合は次です。

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

6. コマンドライン引数とは

ターミナルでは、実行ファイル名の後ろに文字を付けて実行できます。

./greet Haruto

この Haruto のように、プログラムを起動するときに渡す文字列を、コマンドライン引数と呼びます。

たとえば、次のような使い方があります。

指定した名前へあいさつする
↓
指定したファイルを読み込む
↓
指定した件数のデータを処理する
↓
指定した設定でプログラムを動かす

コマンドライン引数を受け取る場合、main 関数を次の形で書きます。

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

最初は長く見えますが、役割を分けると理解しやすくなります。

要素 役割
argc 引数の数
argv 引数として渡された文字列の一覧

7. argc は引数の数

argc は、argument count の略です。

プログラムを起動するときに渡された引数の数が入ります。

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

たとえば、次のように実行します。

./argument_count apple banana

この場合、通常は引数が3つとして扱われます。

argv[0] : ./argument_count
argv[1] : apple
argv[2] : banana

そのため、argc3 です。

実行ファイル名も、通常は先頭の要素として含まれます。

実行ファイル名
+ 利用者が指定した文字列
= argc に入る個数

引数の数を表示する

argument_count.c というファイルを作成してください。

#include <stdio.h>

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

    return 0;
}

コンパイルします。

gcc -std=c17 -Wall -Wextra -Wpedantic argument_count.c -o argument_count

引数を付けずに実行します。

./argument_count

実行結果です。

引数の数: 1

./argument_count 自体が、先頭の要素として数えられているためです。

次に、2つの文字列を付けて実行します。

./argument_count apple banana

実行結果です。

引数の数: 3

8. argv は引数の文字列一覧

argv は、argument vector の略です。

「引数を並べたもの」と考えれば十分です。

char *argv[]

これは、文字列へのポインタを複数まとめたものです。

今は、次のように覚えてください。

argv[0] : 1つ目の文字列
argv[1] : 2つ目の文字列
argv[2] : 3つ目の文字列

argv に出てくる char * の詳しい意味は、ポインタと文字列の理解が進むと分かりやすくなります。

まずは、argv[index] で「起動時に渡された文字列を1つ取り出せる」と考えれば問題ありません。

すべての引数を表示する

show_arguments.c というファイルを作成してください。

#include <stdio.h>

int main(int argc, char *argv[])
{
    // 先頭から最後まで、引数を1つずつ表示します。
    for (int index = 0; index < argc; index++)
    {
        printf("argv[%d]: %s\n", index, argv[index]);
    }

    return 0;
}

コンパイルします。

gcc -std=c17 -Wall -Wextra -Wpedantic show_arguments.c -o show_arguments

次のように実行します。

./show_arguments apple banana

実行結果です。

argv[0]: ./show_arguments
argv[1]: apple
argv[2]: banana

実行環境によって、argv[0] の表示は ./show_arguments ではなく、別のパスやファイル名だけになる場合があります。

ただし、argv[1] 以降には、利用者が指定した文字列が順番に入ります。

9. 引数が足りない場合を確認する

たとえば、「名前を1つ指定して実行するプログラム」を作るとします。

正しい実行方法は、次のとおりです。

./greet Haruto

このとき、必要な引数の数は2つです。

argv[0] : 実行ファイル名
argv[1] : 名前

そのため、argc2 かどうかを確認します。

greet.c というファイルを作成してください。

#include <stdio.h>

int main(int argc, char *argv[])
{
    // 実行ファイル名と名前の、合計2つが必要です。
    if (argc != 2)
    {
        printf("使い方: %s <名前>\n", argv[0]);

        return 1;
    }

    // argv[1] は、利用者が指定した名前です。
    printf("こんにちは、%sさん。\n", argv[1]);

    return 0;
}

コンパイルします。

gcc -std=c17 -Wall -Wextra -Wpedantic greet.c -o greet

名前を指定して実行します。

./greet Haruto

実行結果です。

こんにちは、Harutoさん。

引数を付けずに実行した場合は、次のようになります。

./greet

実行結果です。

使い方: ./greet <名前>

このように、最初に引数の数を確認すると、argv[1] が存在しない状態で使ってしまうミスを防げます。

10. コマンドライン引数は、すべて文字列

コマンドライン引数は、数字に見えても最初は文字列です。

たとえば、次のように実行した場合を考えます。

./repeat_message 3

argv[1] に入っているのは、整数の 3 ではありません。

文字列の "3" です。

argv[1]
↓
"3"

そのため、計算に使うには、文字列を整数へ変換する必要があります。

atoi ではなく strtol を使う

文字列を整数へ変換する関数として、atoi を見かけることがあります。

ただし、atoi は変換できなかった場合と、結果が 0 の場合を区別しにくいため、入力の確認が必要なプログラムには向きません。

このシリーズでは、変換できたかを確認できる strtol を使います。

名前や引数の細かい意味を、この時点で暗記する必要はありません。

まずは、次の3点を覚えれば十分です。

strtol は文字列を整数へ変換する
↓
変換できたかを確認できる
↓
変換に失敗した場合は、処理を止められる

指定した回数だけメッセージを表示する

repeat_message.c というファイルを作成してください。

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

int main(int argc, char *argv[])
{
    // 実行ファイル名と回数の、合計2つが必要です。
    if (argc != 2)
    {
        printf("使い方: %s <回数>\n", argv[0]);

        return 1;
    }

    // 変換できなかった位置を受け取るためのポインタです。
    char *end_pointer = NULL;

    // strtol が数値の範囲外を検出したかを確認するため、最初に 0 にします。
    errno = 0;

    // argv[1] の文字列を、10進数の整数として変換します。
    long repeat_count = strtol(argv[1], &end_pointer, 10);

    // 次のどれかに当てはまる場合は、正しい回数として扱いません。
    // - 数値の範囲外だった
    // - 数字を1文字も読み取れなかった
    // - 数字の後ろに、数字以外の文字が残っている
    // - int 型へ入れられる範囲を超えている
    // - 0未満である
    if (errno == ERANGE ||
        end_pointer == argv[1] ||
        *end_pointer != '\0' ||
        repeat_count < 0 ||
        repeat_count > INT_MAX)
    {
        printf("0以上の整数を指定してください。\n");

        return 1;
    }

    // long から int へ変換しても問題ないことを確認した後で変換します。
    int count = (int)repeat_count;

    // 指定された回数だけ、メッセージを表示します。
    for (int index = 0; index < count; index++)
    {
        printf("%d回目: C言語を学んでいます。\n", index + 1);
    }

    return 0;
}

コンパイルします。

gcc -std=c17 -Wall -Wextra -Wpedantic repeat_message.c -o repeat_message

次のように実行します。

./repeat_message 3

実行結果です。

1回目: C言語を学んでいます。
2回目: C言語を学んでいます。
3回目: C言語を学んでいます。

数値ではない文字列を渡した場合は、次のようになります。

./repeat_message three

実行結果です。

0以上の整数を指定してください。

strtol の細部は、今は覚えなくてよい

先ほどのコードには、これまでより多くの要素が出てきます。

errno
char *end_pointer
strtol(argv[1], &end_pointer, 10)

初めて見たときに、すべてを説明できる必要はありません。

ここで重要なのは、次の流れです。

ターミナルから "3" が渡される
↓
argv[1] に文字列として入る
↓
strtol で数値へ変換する
↓
変換できたかを確認する
↓
変換後の数値を for 文で使う

ポインタについては、先にこちらの記事を読むと char *end_pointer&end_pointer を理解しやすくなります。

C言語のポインタ入門|「値」と「場所」を分けて考える

11. main 関数の書き方を選ぶ基準

最初は、次の基準で使い分けてください。

やりたいこと 書き方
起動時に外から値を受け取らない int main(void)
起動時にターミナルから文字列を受け取る int main(int argc, char *argv[])
void main を使う 新しく書くコードでは使わない

学習用の小さなプログラムでは、ほとんどの場合、次の形で十分です。

int main(void)
{
    /* 処理 */

    return 0;
}

ファイル名や設定値、処理件数などをターミナルから指定できるようにしたい場合だけ、次の形へ変えます。

int main(int argc, char *argv[])
{
    /* 処理 */

    return 0;
}

12. 動かしながら試す課題

課題1:引数をすべて表示する

argv を使い、指定された引数をすべて表示してください。

実行例です。

./show_arguments red green blue

期待する表示例です。

argv[0]: ./show_arguments
argv[1]: red
argv[2]: green
argv[3]: blue

課題2:名前を2つ受け取る

次のように、名前を2つ指定して実行するプログラムを作ってください。

./greet_two_names Haruto Hana

期待する表示例です。

こんにちは、HarutoさんとHanaさん。

名前が1つだけ、または3つ以上指定された場合は、使い方を表示してください。

使い方: ./greet_two_names <名前1> <名前2>

課題3:指定した数までの合計を求める

次のように実行したとき、1から指定した数までの合計を表示してください。

./sum_to 10

期待する表示です。

1から10までの合計は55です。

数値以外が指定された場合は、エラーとして終了してください。

まとめ

main 関数は、プログラムの入口です。

最初は、次の書き方を使えば十分です。

int main(void)

この書き方は、次の意味です。

起動時に値を受け取らない
↓
main 関数から処理を始める
↓
return 0; で正常終了を返す

ターミナルから文字列を受け取りたい場合は、次の形を使います。

int main(int argc, char *argv[])
argc
= 引数の数

argv
= 引数の文字列一覧

void main(void) は、一部の環境で見かける場合があります。

ただし、WSL + GCC で標準的なCとして学ぶ場合、新しく書くコードでは使いません。

int main(void)

または、コマンドライン引数が必要な場合は次です。

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

に統一してください。

次は、商品・社員・センサー情報のように、複数の項目を1件のデータとして扱うために、構造体、typedefenum、構造体の配列を学ぶと、扱えるプログラムの幅が広がります。

C言語でデータをまとめて扱う|構造体・typedef・enum・構造体配列

0
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?