第15回|C言語で関数と配列の受け渡しを学ぶ:配列を処理する関数を作る

当サイトでは、コンテンツの一部に広告を掲載しています。
第15回|C言語で関数と配列の受け渡しを学ぶ:配列を処理する関数を作る

はじめてのC言語 | 第15回

目次

はじめに

前回は、文字列処理の基本を学びました。
今回は、配列を関数に渡して処理する方法を整理します。

配列を使うプログラムでは、合計を求める、最大値を探す、要素を表示する、といった処理を関数に分ける場面が多くあります。
関数に分けることで、同じ処理を何度も書かずに使えるようになります。

この回の目的は次の5点です。

  • 配列を関数に渡す基本形を理解する
  • 要素数を一緒に渡す理由を確認する
  • 配列の合計を求める関数を作る
  • 配列の最大値を求める関数を作る
  • 関数を小さく分ける考え方を学ぶ

配列を関数に渡す基本形

配列を関数に渡すときは、配列名を引数に書きます。
関数側では、配列の先頭要素を指すポインタとして受け取ります。

基本形は次のようになります。

void print_array(int arr[], int size)

または次のようにも書けます。

void print_array(int *arr, int size)

この2つは、関数の引数としてはほぼ同じ意味で使われます。
初学者の段階では、配列を受け取る関数では 配列要素数 をセットで渡す、と覚えてください。

配列を表示する関数を作る

ソースコード

array_function_print.c という名前で保存します。

#include <stdio.h>

void print_array(int arr[], int size) {
    int i;

    for (i = 0; i < size; i++) {
        printf("%d\n", arr[i]);
    }
}

int main(void) {
    int scores[4] = {80, 90, 75, 100};

    print_array(scores, 4);

    return 0;
}

実行手順

1. 作業ディレクトリに移動する

cd ~/Desktop

2. コンパイルする

clang array_function_print.c -o array_function_print

3. 実行する

./array_function_print

実行結果:

80
90
75
100

コードの読み方

void print_array(int arr[], int size)

void print_array(int arr[], int size)

これは、int の配列と要素数を受け取る関数です。
arr は配列の先頭要素を指すものとして扱われます。

print_array(scores, 4);

print_array(scores, 4);

ここでは、配列 scores と要素数 4 を関数に渡しています。
関数の中では、arr[0] から arr[3] までを表示します。

なぜ要素数も渡すのか

配列を関数に渡すと、関数側では配列全体の要素数を自動では判断できません。
関数に渡されるのは、主に先頭要素の場所を表す情報だからです。

そのため、次のように要素数も別の引数として渡します。

print_array(scores, 4);

この 4 がないと、関数はどこまで処理すればよいか分かりません。

配列の合計を求める関数

次に、配列の合計を求める関数を作ります。

#include <stdio.h>

int sum_array(int arr[], int size) {
    int i;
    int sum = 0;

    for (i = 0; i < size; i++) {
        sum += arr[i];
    }

    return sum;
}

int main(void) {
    int scores[4] = {80, 90, 75, 100};
    int total;

    total = sum_array(scores, 4);

    printf("%d\n", total);

    return 0;
}

実行結果:

345

return sum;

sum_array は、配列の合計を計算して int の値として返します。
そのため、関数の戻り値の型は int です。

int sum_array(int arr[], int size)

配列の最大値を求める関数

最大値を求める場合は、最初の要素を仮の最大値としておき、残りの要素と比較します。

#include <stdio.h>

int max_array(int arr[], int size) {
    int i;
    int max = arr[0];

    for (i = 1; i < size; i++) {
        if (arr[i] > max) {
            max = arr[i];
        }
    }

    return max;
}

int main(void) {
    int scores[4] = {80, 90, 75, 100};

    printf("%d\n", max_array(scores, 4));

    return 0;
}

実行結果:

100

int max = arr[0];

最初に arr[0] を最大値として扱います。
その後、arr[1] 以降を順番に見て、より大きい値があれば max を更新します。

この関数は、size が1以上であることを前提にしています。
空の配列を渡す設計は、この段階では扱いません。

関数を小さく分ける

配列を扱う処理は、関数に分けると読みやすくなります。

たとえば次のように役割を分けられます。

  • 表示する関数
  • 合計を求める関数
  • 最大値を求める関数

1つの関数に多くの処理を詰め込むよりも、役割ごとに分けたほうが、読みやすく修正しやすいプログラムになります。

int arr[] と int *arr

関数の引数では、次の2つは似た意味で使われます。

void print_array(int arr[], int size)
void print_array(int *arr, int size)

どちらも、関数の中では arr[i] のように添字で要素にアクセスできます。
この連載では、初学者にとって配列を受け取っていることが分かりやすい int arr[] を主に使います。

文字列を関数に渡す

文字列も char 配列なので、関数に渡せます。

#include <stdio.h>

void print_message(char message[]) {
    printf("%s\n", message);
}

int main(void) {
    char text[] = "hello";

    print_message(text);

    return 0;
}

実行結果:

hello

文字列の場合は、終端の '\0' があるため、printf("%s", message); は文字列の終わりを判断できます。
ただし、文字列を書き換える処理では、配列サイズへの注意が必要です。

初心者がつまずきやすい点

要素数を渡し忘れる

配列だけを渡しても、関数の中では要素数が分かりません。
配列を処理する関数には、基本的に要素数も渡します。

size より大きい範囲を読んでしまう

次のようなループは危険です。

for (i = 0; i <= size; i++) {
    printf("%d\n", arr[i]);
}

i <= size では、最後に arr[size] へアクセスしてしまいます。
有効な添字は 0 から size - 1 までです。

正しくは次のように書きます。

for (i = 0; i < size; i++) {
    printf("%d\n", arr[i]);
}

空の配列を考えずに最大値を求める

int max = arr[0]; は、要素が1個以上あることを前提にしています。
要素数が0の場合、arr[0] は使えません。

この回では、最大値を求める関数には要素が1個以上ある配列を渡すものとして扱います。

よくあるエラー

実行結果がおかしい、または異常終了する

原因: size が実際の要素数と合っていない可能性があります。
対処: 配列の要素数と、関数に渡す size の値を確認します。

arr[size] にアクセスしてしまう

原因: ループ条件を i <= size と書いています。
対処: i < size を使います。

関数の戻り値を受け取っていない

原因: sum_array のように値を返す関数を呼び出しているのに、戻り値を使っていません。
対処: 変数に代入するか、printf の中で使います。

int total = sum_array(scores, 4);

練習用コード

平均点を表示する

#include <stdio.h>

int sum_array(int arr[], int size) {
    int i;
    int sum = 0;

    for (i = 0; i < size; i++) {
        sum += arr[i];
    }

    return sum;
}

int main(void) {
    int scores[5] = {70, 80, 90, 60, 100};
    int total;

    total = sum_array(scores, 5);

    printf("%d\n", total / 5);

    return 0;
}

最小値を求める

#include <stdio.h>

int min_array(int arr[], int size) {
    int i;
    int min = arr[0];

    for (i = 1; i < size; i++) {
        if (arr[i] < min) {
            min = arr[i];
        }
    }

    return min;
}

int main(void) {
    int values[4] = {12, 5, 30, 8};

    printf("%d\n", min_array(values, 4));

    return 0;
}

実行結果:

5

まとめ

今回のポイントは次のとおりです。

  • 配列は関数に渡して処理できる
  • 関数には配列と要素数を一緒に渡す
  • 関数側では配列の要素数を自動では判断できない
  • 合計や最大値のような処理は関数に分けると再利用しやすい
  • ループでは 0 から size - 1 までを処理する
  • int arr[]int *arr は関数引数では似た意味で使われる

この回では、配列を関数に渡して処理する方法を学びました。
配列を扱う関数では、配列そのものだけでなく、要素数も一緒に渡すことが重要です。

次回予告

次は、構造体の基本を学びます。
構造体を使うと、複数の値を1つのまとまりとして扱えるようになり、配列や関数と組み合わせたプログラムを書きやすくなります。

あわせて読みたい
第16回|C言語で構造体の基本を学ぶ:複数の値を1つのまとまりとして扱う はじめてのC言語 | 第16回 はじめに 前回は、関数と配列の受け渡しを学びました。今回は、C言語の「構造体」を学びます。 構造体を使うと、複数の値を1つのまとまりと...

さらに学びたいあなたへ

用途ごとに選ぶ Linux のおすすめ本

よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!

この記事を書いた人

のいのアバター のい UNIX Cafe マスター

Macintosh Color Classicから始まった旅は、長いWindows時代を経て、Windows10のサポート終了をきっかけにUNIXの世界へ戻ってきました。UNIX Cafeでは、UNIX・Linux・そしてMacな世界を、むずかしい言葉を使わず、物語のように書いています。プログラミングは、アイデアをコンピューターに伝えるための言葉です。簡単な単語と文法を覚えれば、誰でもコマンドを使えます。ぜひ一度、やさしいプログラミングの世界をのぞいてみてください。

Created by UNIX Cafe

目次