C言語の関数のサンプルを11例解説

537, 2022-08-17

目次

C言語の関数の作例(サンプル)

今回はC言語の関数のサンプルをいくつか解説します。
C言語では関数を定義できますが色々な定義方法があります。

この記事を読んでおけばC言語にはどういった関数の定義があるのかわかると思います。

関連記事

サンプル1: 返り値なし引数なし

サンプルの1つ目は「返り値なし」「引数なし」の関数です。

void func1(void) {
}

返り値も引数も存在しないことを示す場合は「void」を使います。
関数の構造については大丈夫ですか?
一応おさらいしておきますが↓が関数の構造です。

返り値 関数名(引数) {
    処理;
}

↑の「返り値」と「引数」の部分に「void」を使うと返り値も引数も持たない関数になります。

このような関数は意外と使い道が多いです。
たとえばprintf()などで出力だけする関数などこういった設計の関数を使います。
もっとも基本的な関数とも言えるでしょう。

サンプル2: 返り値あり引数なし

今度は返り値がある場合です。
引数はないです。
ここでは返り値は「int」型にしています。

int getint(void) {
    return 123;
}

この関数は返り値として整数「123」を返します。
「123」はint型でこの関数の返り値の型もint型です。

この関数は例えば↓のように使えます。

    int n = getint();

    printf("%d\n", n);  // 123

関連記事
C言語の関数で戻り値を返す方法【return文】

サンプル3: 返り値なし引数あり

次は引数ありで返り値がない場合です。
引数の型は「int」型にしています。

void putint(int n) {
    printf("%d\n", n); 
}

↑の関数は引数にintのnを取ります。
そして関数の内部ではprintf()で引数nを出力しています。

この関数はたとえば↓のように使います。

    putint(123);  // 123

返り値はvoid型なのでありません。
このパターンの関数もよく使われます。
返り値が必要ないときはたいていこのパターンになります。

関連記事
C言語の関数ポインタを引数に渡す方法
C言語の関数の引数の使い方

サンプル4: 返り値あり引数あり

これは返り値も引数もある場合です。
返り値はint, 引数もintにしてあります。

int add(int a, int b) {
    return a + b;
}

この関数は引数を2つ取ります。aとbです。
そしてaとbを足し算した結果を返り値として返しています。

この関数はたとえば↓のように使います。

    int c = add(1, 2);

    printf("%d\n", c);  // 3

関連記事
C言語の関数で戻り値を返す方法【return文】
C言語の関数の引数の使い方
C言語の関数ポインタを引数に渡す方法

サンプル5: ポインタを引数に取る関数

C言語でよく使われるパターンの1つがこれです。
引数にポインタを使うケースです。

void bai(int *p) {
    *p *= 2;
}

↑の関数は引数のint型のポインタ変数を参照してその実体を倍の値にする関数です。
この関数は例えば↓のように使います。

    int bai_a = 2;
    bai(&bai_a);
    printf("%d\n", bai_a);  // 4

このように関数の引数にポインタを使うとその関数の内部でポインタを通じて変数の値を書き換えることができます。
C言語ではこのパターンの関数は非常によく使われます。
覚えておきたいパターンの1つです。

関連記事
C言語の関数の引数の使い方
C言語の関数ポインタを引数に渡す方法

サンプル6: 返り値にポインタを返す関数

これもC言語ではよく使われるパターンです。
返り値にポインタを返す関数です。

int *baibai(int *p) {
    if (p == NULL) {
        return NULL;
    }

    *p *= 4;

    return p;
}

↑の関数は引数pがNULLだった場合にNULLを返します。
NULLでなければ引数pをそのまま返します。
この関数は引数のポインタの実体を4倍にする関数です。

こういった関数は↓のように使います。

    int baibai_a = 2;
    if (baibai(&baibai_a) == NULL) {
        perror("failed to baibai");
    }

    printf("%d\n", baibai_a);  // 8

baibai()関数は返り値の状態を2つ持っています。
NULLの場合とNULLでない場合です。
このような設計の関数では一般的に返り値がNULLだった場合はその関数が失敗したと見なすことが多いです。
つまりbaibai()がNULLを返したら何らかの理由でその関数の実行が失敗したということです。

返り値がNULLでない場合はその関数は実行に成功している状態と見なします。
このように返り値にポインタを使うと関数の成功/失敗の状態を表現することも出来ます。

関連記事
C言語の関数で戻り値を返す方法【return文】

サンプル7: 構造体を返す関数

C言語の関数は構造体変数を返すことも出来ます。
↓は構造体変数を返す関数です。

struct Animal {
    int age;
    double height;
};

struct Animal getanimal(int age, double height) {
    struct Animal animal = { age, height };
    return animal;
}

この関数は↓のように使います。

    struct Animal animal1 = getanimal(20, 170);

    printf("age: %d\n", animal1.age);
    printf("height: %f\n", animal1.height);

この設計では関数が構造体の変数を返すときにコピーが発生します。
つまり構造体変数のメンバのコピーです。
ですので構造体が巨大なメンバを持っている場合はその分のコピーも発生する場合があります。
この辺はコンパイラの最適化次第で何とも言えないところですが、計測してみてください。

関連記事
C言語の構造体を関数で扱う

サンプル8: 構造体のポインタを引数に取る関数

これもC言語では非常によく使われるパターンです。
構造体のポインタを引数に取る関数です。

void setage(struct Animal *animal, int age) {
    animal->age = age;
}

この関数は例えば↓のように使います。

    struct Animal animal2 = { 20, 170 };
    setage(&animal2, 30);
    printf("age: %d\n", animal2.age);  // 30

このように構造体のポインタを第1引数に取って第2引数以降に処理用の引数を指定する設計は例えばfopen()系の関数などがこういう設計になっています。
この設計はオブジェクト指向的でこの設計を好んでいる開発者も非常に多いです。

関連記事
C言語のfopen関数でファイルを開く方法【fcloseも解説】
C言語で構造体を引数に渡す方法
C言語の構造体を関数で扱う

サンプル9: 読み込み専用な構造体のポインタを引数に取る関数

関数の引数の構造体のポインタにconstを付けると読み込み専用になります。
これを利用してメンバを変更する予定がない関数の場合はポインタにconstを付けるのが一般的に行われます。

void showanimal(const struct Animal *animal) {
    printf("age: %d\n", animal->age);
    printf("height: %f\n", animal->height);    
}

この関数は↓のように使います。

    struct Animal animal3 = { 20, 170 };
    showanimal(&animal3);
    // age: 20
    // height: 170

構造体のメンバを読み込みだけして変更する予定がない場合はconstを付けたほうが良いでしょう。
このような設計はC/C++などの言語では一般的です。
constを付けると設計が多少複雑になるのでその辺は状況を見て選択しましょう。

関連記事
C言語の構造体を関数で扱う

サンプル10: 構造体変数を引数に取る関数

もちろん構造体変数はポインタでなくそのまま渡すことも出来ます。

void showanimal2(struct Animal animal) {
    printf("age: %d\n", animal.age);
    printf("height: %f\n", animal.height);
}

この関数は↓のように使います。

    struct Animal animal4 = { 20, 170 };
    showanimal2(animal4);
    // age: 20
    // height: 170

構造体変数を引数にそのまま渡すとメンバ変数のコピーが発生することがあります。
ですのでパフォーマンス(速度)を気にする場合はポインタを使ったほうがいいでしょう。

関連記事
C言語で構造体を引数に渡す方法
C言語の構造体を関数で扱う

サンプル11: 可変長引数を取る関数

関数は可変長引数を取ることも出来ます。

#include <stdio.h>
#include <stdarg.h>

void myprintf(const char *fmt, ...) {
    char dst[1024];

    va_list ap;
    va_start(ap, fmt);
    vprintf(fmt, ap);
    va_end(ap);
}

int main(void) {
    myprintf("Hello, %s\n", "World!");
    return 0;
}

↑の関数は可変長引数の...を使ってmyprintf()関数を定義しています。
このように可変長引数を使うと柔軟な関数の設計も可能です。
ただC言語では可変長引数の取り扱いはわりとめんどくさいので設計に組み込む人はあまり見かけないかもしれません。

(^ _ ^)

さすがC言語

(・ v ・)

スパルタC言語

関連記事
C言語のprintfの簡単な使い方: フォーマット文字列と引数

おわりに

今回はC言語の関数のサンプルを解説しました。
ここら辺の関数の作り方を押さえておけばたいていは大丈夫だと思われます。

(^ _ ^)

C言語の関数を学ぼう

(・ v ・)

関数はマブダチ



この記事のアンケートを送信する