【C言語入門】main関数完全ガイドと10の実践的なサンプルコード

C言語のmain関数について学ぶための記事のサムネイル C言語

 

【サイト内のコードはご自由に個人利用・商用利用いただけます】

このサービスはSSPによる協力の下、運営されています。

この記事では、プログラムの基礎知識を前提に話を進めています。

説明のためのコードや、サンプルコードもありますので、もちろん初心者でも理解できるように表現してあります。

基本的な知識があればカスタムコードを使って機能追加、目的を達成できるように作ってあります。

※この記事は、一般的にプロフェッショナルの指標とされる『実務経験10,000時間以上』を凌駕する現役のプログラマチームによって監修されています。

サイト内のコードを共有する場合は、参照元として引用して下さいますと幸いです

※Japanシーモアは、常に解説内容のわかりやすさや記事の品質に注力しております。不具合、分かりにくい説明や不適切な表現、動かないコードなど気になることがございましたら、記事の品質向上の為にお問い合わせフォームにてご共有いただけますと幸いです。
(送信された情報は、プライバシーポリシーのもと、厳正に取扱い、処分させていただきます。)

はじめに

プログラミングを学ぶにあたり、多くの人が最初に触れるのが「C言語」でしょう。

特に、初心者が最初に学ぶ関数として「main関数」があります。

本記事では、C言語のmain関数について詳細に解説します。

その基本的な使い方やサンプルコード、注意点、カスタマイズ方法についても触れていきますので、初めてプログラミングを学ぶ方にも分かりやすい内容となっています。

●C言語とは?

C言語は、1972年にAT&Tベル研究所で開発されたプログラミング言語で、その効率の良さと直感的な文法により、OSや組み込みシステムの開発に広く用いられています。

また、他の多くのプログラミング言語の基礎ともなっており、C言語を理解することはプログラミング全体の理解に繋がると言えます。

●main関数とは?

○main関数の概念

main関数はC言語における特別な関数で、プログラムが実行されると最初に呼び出される関数です。

プログラムの実行はmain関数から始まり、main関数が終了するとプログラムも終了します。

main関数は他の関数とは異なり、プログラム内に一つしか存在することができません。

○main関数の構成要素

main関数の基本的な形は次のようになります。

int main() {
  // 処理
  return 0;
}

ここで、「int main()」は関数の宣言部分で、「return 0;」は関数の終了を意味します。

0を返すことで、プログラムが正常に終了したことをOSに伝えます。

●main関数の使い方

○基本的な書き方

main関数の基本的な書き方は先程示した通りですが、中括弧「{」と「}」の間に処理を記述することで、プログラムが実行する内容を指定します。

int main() {
  printf("Hello, World!");
  return 0;
}

このコードでは、”Hello, World!”というメッセージを画面に表示します。

○引数の利用方法

main関数では引数を取ることも可能です。

その際の形式は次のようになります。

int main(int argc, char *argv[]) {
  // 処理
  return 0;
}

ここで、「int argc」はコマンドライン引数の数を、「char *argv[]」はコマンドライン引数の内容を表します。

○戻り値の利用方法

先程も説明したように、main関数の戻り値はプログラムの終了状態をOSに伝えるために使います。

0を返すと正常終了、それ以外を返すと異常終了を示します。

●サンプルコード:C言語main関数の例

ここでは、具体的なサンプルコードを通じて、main関数の使い方を見ていきます。

○サンプルコード1:最も単純なmain関数

int main() {
  return 0;
}

このコードは何も行わず、ただプログラムを正常終了させるmain関数です。

○サンプルコード2:引数を取るmain関数

次に、引数を取るmain関数の例を見ていきましょう。

int main(int argc, char *argv[]) {
  for (int i = 0; i < argc; i++) {
    printf("%s\n", argv[i]);
  }
  return 0;
}

このコードは、コマンドライン引数をすべて表示するプログラムです。引数は「argv[0]」から始まり、「argv[argc-1]」まで存在します。

○サンプルコード3:戻り値を持つmain関数

int main() {
  // 処理
  return 1;
}

このコードは、プログラムを異常終了させるmain関数です。

1を返すと異常終了を示します。

○サンプルコード4:コマンドライン引数を取るmain関数

C言語では、プログラムが起動される際にコマンドラインから引数を受け取ることが可能です。

そのために使用するのが、main関数の引数として用意されている int argc, char *argv[] です。

下記のサンプルコードは、コマンドライン引数を取るmain関数の例です。

#include <stdio.h>

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

このコードでは、コマンドライン引数を使って文字列を出力するプログラムを作成しています。

この例では、argcargv を使って、プログラム起動時に指定された引数を全て出力しています。

argc は、コマンドラインから渡された引数の数を表します。

プログラム名も引数としてカウントされますので、引数がない場合でもargcは最低でも1となります。

一方、argv は、引数の値を保持する文字列配列です。

argv[0]はプログラム名、argv[1]以降がコマンドライン引数となります。

コードを実行すると、次のような出力が得られます。

例えば、”Hello” “World” という2つの引数をプログラムに渡すと、次のような結果になります。

$ ./a.out Hello World
argv[0] = ./a.out
argv[1] = Hello
argv[2] = World

./a.outがプログラム名(argv[0])、”Hello”と”World”がコマンドライン引数(argv[1]argv[2])です。

このように、argcargvを使用することで、プログラム起動時に外部からデータを受け取ることができます。

この機能は非常に便利で、ファイル名や設定値など、プログラムの動作を外部から制御するためによく使用されます。

しかし、コマンドライン引数の取り扱いには注意が必要で、その詳細は後ほど詳しく説明します。

○サンプルコード5:コマンドライン引数と戻り値を活用したmain関数

下記のサンプルコードでは、C言語のmain関数におけるコマンドライン引数と戻り値の活用方法を具体的に説明します。

具体的には、コマンドラインから入力された数値を合計し、その結果を戻り値として出力するプログラムを作成します。

このコードは、コマンドライン引数と戻り値を同時に理解し、効果的に活用するための良い例です。

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

// コマンドライン引数と戻り値を活用したmain関数
int main(int argc, char *argv[]) {
    int sum = 0;

    // コマンドライン引数の数値を全て合計する
    for (int i = 1; i < argc; i++) {
        sum += atoi(argv[i]);
    }

    printf("合計: %d\n", sum);

    // 合計値を戻り値として返す
    return sum;
}

このコードでは、まずmain関数の引数としてint型のargcとchar型のポインタ配列argvを取ります。

argcはコマンドライン引数の数を表し、argvはそれら引数の内容を表します。

次に、for文を用いてargvの各要素(つまりコマンドラインから与えられた各数値)を取り出し、atoi関数を用いてそれらを整数に変換し、sumに加算しています。

最後に、printf関数で合計値を出力し、その合計値をmain関数の戻り値として返しています。

このコードを実行するときは、例えば次のようにコマンドラインから数値を引数として渡します。

$ gcc sum.c -o sum
$ ./sum 1 2 3 4 5
合計: 15

以上の結果からわかるように、このプログラムはコマンドラインから与えられた各数値(この例では1, 2, 3, 4, 5)を合計し、その結果を出力しています。

また、戻り値としてもこの合計値を返すため、他のプログラムやシェルスクリプトからこの戻り値を取得することも可能です。

●main関数の注意点と対処法

ここでは、C言語のmain関数を使用する際に気をつけるべき注意点とその対処法を紹介します。

正しくmain関数を使うことで、プログラム全体の品質を向上させることができます。

○注意点1:main関数の呼び出し方

main関数は、プログラムの実行開始地点となる特殊な関数です。

そのため、プログラム内から直接呼び出すことは推奨されません。

なぜなら、その結果としてプログラムの実行フローが複雑になり、理解しづらいコードにつながる可能性があるからです。

一方で、再帰的な動作が必要な特殊なケースでは、main関数を呼び出すこともありますが、そのようなケースはほとんどないと考えて良いでしょう。

○注意点2:コマンドライン引数の扱い

コマンドライン引数は、main関数で受け取ることができるパラメータの一種です。

これはプログラムがコマンドラインから呼び出される際に、ユーザーからの入力を受け取るためのものです。

ただし、コマンドライン引数は、型チェックが行われないため、入力データの検証が重要です。

間違った型のデータを受け取ると、プログラムは予期しない挙動を表すことがあります。

○注意点3:戻り値の活用

main関数の戻り値は、プログラムが正常に終了したかどうかを表す重要な情報源です。

しかし、この戻り値を適切に活用しないと、エラーハンドリングが不十分になり、プログラムの信頼性を低下させる可能性があります。

一般的に、main関数からの戻り値は0であればプログラムは正常に終了したことを示し、それ以外の値は何らかのエラーが発生したことを表します。

○対処法1:main関数のエラーハンドリング

main関数でエラーハンドリングを行う一つの方法は、プログラム全体のエラーチェックをmain関数で行うことです。

具体的には、必要なリソースの確保や初期化が成功したかどうかをチェックし、問題があれば適切なエラーメッセージを出力してプログラムを終了します。

例えば、次のコードでは、ファイルのオープンに失敗した場合にエラーメッセージを出力し、非ゼロの値を返してプログラムを終了しています。

#include <stdio.h>

int main(void) {
  // ファイルをオープンします
  FILE *file = fopen("test.txt", "r");

  // ファイルのオープンに失敗した場合
  if (file == NULL) {
    // エラーメッセージを出力します
    printf("エラー: ファイルを開くことができませんでした。\n");
    // エラーのステータスコードを返します
    return 1;
  }

  // 省略
  return 0;
}

このコードでは、fopen関数を使ってファイルを開きます。

そして、fopenNULLを返した場合、つまりファイルのオープンに失敗した場合にはエラーメッセージを出力し、非ゼロの値を返してプログラムを終了しています。

○対処法2:コマンドライン引数のエラーハンドリング

コマンドライン引数のエラーハンドリングも非常に重要です。

ユーザーからの入力は必ずしも期待した形式であるとは限らないため、この検証が不十分だと、予期しない動作やエラーを引き起こす可能性があります。

それを防ぐために、main関数の中で入力の妥当性をチェックし、問題があればエラーメッセージを表示するようにすることが重要です。

下記のサンプルコードは、コマンドライン引数を取り、それが整数であることを検証する簡単な例です。

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

int main(int argc, char *argv[]) {
  // コマンドライン引数が1つであることを確認します
  if (argc != 2) {
    printf("エラー: 引数は1つ必要です。\n");
    return 1;
  }

  // 引数が整数であることを確認します
  char *endptr;
  long num = strtol(argv[1], &endptr, 10);
  if (*endptr != '\0') {
    printf("エラー: 引数は整数である必要があります。\n");
    return 1;
  }

  // 省略
  return 0;
}

このコードでは、まずargc(コマンドライン引数の数)が2であることを確認しています。

argcが2でない場合、つまり引数が1つでない場合にはエラーメッセージを出力し、プログラムを終了しています。

次に、strtol関数を使用して、引数が整数であることを確認しています。

strtol関数は、文字列を整数に変換しますが、変換できない部分がある場合にはその位置をendptrに設定します。

そのため、*endptr'\0'でない場合、つまり引数が整数でない場合にはエラーメッセージを出力し、プログラムを終了しています。

●main関数のカスタマイズ方法

C言語のmain関数は、カスタマイズが可能で、ユーザーのニーズに応じてより柔軟に機能を追加することができます。

ここでは、main関数のカスタマイズの一例として、自作ライブラリの利用とグローバル変数の活用の2つを紹介します。

○カスタマイズ例1:自作ライブラリの利用

自作のライブラリを利用することで、より効率的にプログラムを作成することができます。

例えば、数学的な計算を頻繁に行うプログラムを作成する場合、その都度計算ロジックを記述するのは非効率です。

そこで、計算ロジックを自作ライブラリとしてまとめ、それをmain関数から呼び出すことで、プログラムの見通しを良くすることができます。

自作のライブラリを利用したmain関数のサンプルコードを紹介します。

#include <stdio.h>
#include "my_math.h"  // 自作ライブラリのヘッダーファイルをインクルード

int main() {
    double x = 3.0;
    double y = 4.0;
    double result = my_add(x, y);  // 自作ライブラリの関数を使用
    printf("結果: %f\n", result);
    return 0;
}

このコードでは、まず#include "my_math.h"により自作ライブラリのヘッダーファイルをインクルードしています。

そして、my_add(x, y)という形で自作ライブラリの関数を呼び出しています。

この例では、自作ライブラリに含まれるmy_add関数を使って、変数xとyを加算しています。

このコードを実行すると、「結果: 7.000000」と表示されます。

これは、自作ライブラリのmy_add関数が、引数として与えられたxとyを加算した結果を表示しているためです。

○カスタマイズ例2:グローバル変数の活用

main関数内だけでなく、プログラム全体で共有したい変数がある場合には、グローバル変数を活用すると便利です。

グローバル変数は、プログラムのどの部分からでもアクセスできる変数で、関数間でデータを共有するのに使用します。

グローバル変数を活用したmain関数のサンプルコードを紹介します。

#include <stdio.h>

int global_var;  // グローバル変数の定義

void add_ten() {
    global_var += 10;
}

int main() {
    global_var = 20;
    printf("初期値: %d\n", global_var);
    add_ten();
    printf("10を加算後の値: %d\n", global_var);
    return 0;
}

このコードでは、まずint global_var;によりグローバル変数を定義しています。

そして、add_ten関数内でグローバル変数の値を変更しています。

main関数内でadd_ten関数を呼び出すことで、グローバル変数の値を変更することが可能です。

この例では、main関数内でグローバル変数に20を代入し、その後、add_ten関数を呼び出してグローバル変数に10を加算しています。

このコードを実行すると、「初期値: 20」、「10を加算後の値: 30」と表示されます。

これは、main関数内でグローバル変数に20を代入し、その後でadd_ten関数を呼び出して10を加算した結果を表示しているためです。

このようにグローバル変数を活用することで、複数の関数間で値を共有することが可能となります。

●応用例:サンプルコードとその解説

では、これまでに学んだC言語のmain関数の知識を基に、さまざまな具体的な応用例を見ていきましょう。

各応用例には実際のサンプルコードを掲載し、それぞれのコードの動作や注意点を詳しく解説します。

○応用例1:ファイル操作を行うmain関数

C言語では、標準ライブラリの一部としてファイル操作関数が提供されています。

これを活用すると、main関数から直接ファイルを読み書きすることができます。

下記のコードは、”test.txt”という名前のファイルに”Hello, World!”という文字列を書き込む例です。

#include <stdio.h>

int main(void) {
    FILE *fp;
    fp = fopen("test.txt", "w");
    if (fp == NULL) {
        printf("ファイルを開けませんでした。\n");
        return 1;
    }
    fprintf(fp, "Hello, World!");
    fclose(fp);

    return 0;
}

このコードでは、fopen関数を使ってファイルを開き、fprintf関数でファイルに文字列を書き込み、fclose関数でファイルを閉じています。

もし何らかの理由でファイルが開けなかった場合は、エラーメッセージを出力して異常終了します。

このコードを実行すると、実行したディレクトリに”test.txt”という名前のファイルが作成され、その中に”Hello, World!”と書かれています。

エラーハンドリングも行っているため、ファイルが開けないなどの問題が起きても適切に対処することができます。

○応用例2:ネットワーク通信を行うmain関数

次に、ネットワーク通信を行うmain関数の例を見てみましょう。

C言語では、socketライブラリを利用してネットワーク通信を行うことができます。

下記のコードは、特定のIPアドレスとポートに対してHTTPリクエストを送信し、レスポンスを表示する例です。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h> 

void error(const char *msg)
{
    perror(msg);
    exit(0);
}

int main(int argc, char *argv[])
{
    int sockfd, portno, n;
    struct sockaddr_in serv_addr;
    struct hostent *server;

    char buffer[256];
    if (argc < 3) {
       fprintf(stderr,"使用法 %s hostname port\n", argv[0]);
       exit(0);
    }
    portno = atoi(argv[2]);
    sockfd = socket(AF_INET, SOCK_STREAM, 0);
    if (sockfd < 0) 
        error("エラー:ソケットのオープンに失敗しました");
    server = gethostbyname(argv[1]);
    if (server == NULL) {
        fprintf(stderr,"エラー:ホストが存在しません\n");
        exit(0);
    }
    bzero((char *) &serv_addr, sizeof(serv_addr));
    serv_addr.sin_family = AF_INET;
    bcopy((char *)server->h_addr, 
         (char *)&serv_addr.sin_addr.s_addr,
         server->h_length);
    serv_addr.sin_port = htons(portno);
    if (connect(sockfd,(struct sockaddr *) &serv_addr,sizeof(serv_addr)) < 0) 
        error("エラー:接続に失敗しました");
    printf("メッセージを入力してください: ");
    bzero(buffer,256);
    fgets(buffer,255,stdin);
    n = write(sockfd,buffer,strlen(buffer));
    if (n < 0) 
         error("エラー:ソケットへの書き込みに失敗しました");
    bzero(buffer,256);
    n = read(sockfd,buffer,255);
    if (n < 0) 
         error("エラー:ソケットからの読み取りに失敗しました");
    printf("%s\n",buffer);
    close(sockfd);
    return 0;
}

このコードでは、socket関数でソケットを生成し、gethostbyname関数でホストの情報を取得してからconnect関数でサーバに接続します。

その後、write関数でメッセージを送信し、read関数でレスポンスを読み取っています。

途中で何らかのエラーが発生した場合は、その旨を出力してプログラムを終了します。

このプログラムを実行する際は、引数としてホスト名とポート番号を指定する必要があります。

例えば、”localhost”のポート80に対して通信を行いたい場合は、”./a.out localhost 80″というように指定します。

○応用例3:マルチスレッド処理を行うmain関数

C言語では、pthreadライブラリを用いてマルチスレッド処理を行うことができます。

下記のコードは、2つのスレッドを作成し、それぞれが異なる処理を並行に行う例です。

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

void *print_message_function( void *ptr );

int main()
{
    pthread_t thread1, thread2;
    char *message1 = "スレッド1";
    char *message2 = "スレッド2";
    int  iret1, iret2;

    iret1 = pthread_create( &thread1, NULL, print_message_function, (void*) message1);
    iret2 = pthread_create( &thread2, NULL, print_message_function, (void*) message2);

    pthread_join( thread1, NULL);
    pthread_join( thread2, NULL); 

    printf("スレッド1は%dを返しました\n", iret1);
    printf("スレッド2は%dを返しました\n", iret2);
    exit(0);
}

void *print_message_function( void *ptr )
{
    char *message;
    message = (char *) ptr;
    printf("%s \n", message);
}

このコードでは、pthread_create関数を用いて2つのスレッドを作成し、それぞれに異なるメッセージを渡しています。

各スレッドは、print_message_function関数内でそのメッセージを表示します。

main関数は、pthread_join関数で各スレッドの終了を待ち、その結果を表示します。

このプログラムを実行すると、”スレッド1″と”スレッド2″というメッセージが並行に表示され、その後に各スレッドの終了結果が表示されます。

○応用例4:データベース接続を行うmain関数

データベースとの接続は、Webアプリケーション開発や情報管理システムの作成など、多くの場面で必要となる技術です。

今回は、C言語のmain関数を用いてMySQLデータベースへの接続と簡単なデータの取得を行うサンプルコードを紹介します。

まずは、mysql.hヘッダーファイルを含めて、MySQLのC APIを使用できるようにします。

このヘッダーファイルはMySQLのCライブラリに含まれており、その機能をCプログラムから利用することを可能にします。

下記のサンプルコードは、main関数内でMySQLへの接続とデータ取得を行うものです。

#include <mysql.h>
#include <stdio.h>

int main() {
    MYSQL *conn;
    MYSQL_RES *res;
    MYSQL_ROW row;

    char *server = "localhost";
    char *user = "username";
    char *password = "password";
    char *database = "dbname";

    conn = mysql_init(NULL);

    if (!mysql_real_connect(conn, server, user, password, database, 0, NULL, 0)) {
        fprintf(stderr, "%s\n", mysql_error(conn));
        return 1;
    }

    if (mysql_query(conn, "SELECT * FROM table")) {
        fprintf(stderr, "%s\n", mysql_error(conn));
        return 1;
    }

    res = mysql_use_result(conn);

    while ((row = mysql_fetch_row(res)) != NULL)
        printf("%s \n", row[0]);

    mysql_free_result(res);
    mysql_close(conn);

    return 0;
}

このコードでは、mysql_init関数でMySQLの接続を初期化し、その後mysql_real_connect関数でデータベースへ接続を行っています。

接続情報は先頭で定義された変数により指定されます。

その後、mysql_query関数を使ってSQLクエリを実行し、その結果をmysql_use_result関数で取得します。

取得した結果はmysql_fetch_row関数で一行ずつ取り出され、その結果が画面に表示されます。

最後に、mysql_free_result関数とmysql_close関数を使って、結果セットと接続を適切に閉じています。

これらはリソースの解放とメモリリーク防止のために必須のステップです。

このコードを実行すると、接続したデータベースの指定されたテーブルの全ての行が画面に表示されます。

エラーが発生した場合は、その詳細が表示され、プログラムが終了します。

○応用例5:GUIアプリケーションの作成

C言語を使用してGUIアプリケーションを作成することも可能です。

一般的に、Windows向けのアプリケーションを開発する際には、WinAPIというWindows専用のAPIを使用します。

ここでは、WinAPIを用いて簡単なウィンドウを表示するmain関数の一例を紹介します。

#include <windows.h>

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) {
    MessageBox(NULL, "Hello, World!", "Hello Message", MB_OK);
    return 0;
}

このコードでは、WinAPIの一部であるMessageBox関数を使ってウィンドウを表示しています。

この例では、簡単なメッセージボックスを表示しています。

「Hello, World!」というテキストが表示され、OKボタンをクリックするとプログラムが終了します。

ここで新たに登場したWinMainという関数は、GUIアプリケーションのエントリーポイントとなる関数で、main関数の代わりに用いられます。

WinMain関数には4つの引数があり、それぞれアプリケーションのインスタンスハンドル、前のインスタンスハンドル、コマンドライン引数、ウィンドウの表示状態を表します。

このコードを実行すると、ウィンドウが表示され「Hello, World!」というメッセージと共にOKボタンが表示されます。

OKボタンを押すとウィンドウは閉じ、プログラムは終了します。

しかし、GUIアプリケーションの開発はこの程度の簡単なものだけではありません。

ボタンやテキストボックスなどのウィジェットを配置したり、ウィンドウのサイズを変更するときの挙動を定義したり、さらにはマウスやキーボードからの入力を処理したりするためには、より高度なWinAPIの知識と技術が必要となります。

C言語でGUIアプリケーションを作成する際には、特にWinMain関数の理解と、WinAPIを用いたウィンドウやウィジェットの操作が鍵となります。

GUIアプリケーション開発は、C言語のポテンシャルを最大限に引き出す一方で、C言語の基本的な理解とスキルを深める絶好の機会でもあります。

このようなGUIアプリケーションの作成は、初心者から中級者までのC言語学習者にとっては、非常に興味深いプロジェクトであると言えるでしょう。

しかし、この領域は高度な知識と経験を必要とするため、基本的なC言語の知識とmain関数の使用方法をしっかりと理解した上で挑戦することを強く推奨します。

まとめ

この記事では、C言語のmain関数について詳細に解説しました。

基本的な作り方から使い方、注意点、カスタマイズ方法まで、幅広い内容を取り扱いました。

また、具体的なサンプルコードとその応用例も掲載しました。

C言語のmain関数は、プログラムのエントリーポイントとなり、その機能と役割は非常に重要です。

そのため、C言語を学び始めた方は、main関数の使い方をしっかりと理解し、多様な応用例を通じてその知識を深めることが大切です。

プログラミングは、概念を理解し、それを実際のコードに落とし込む能力が求められます。

この記事が、C言語とmain関数についての理解を深め、実際のコーディングスキルを向上させる一助となれば幸いです。