
はじめての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 ~/Desktop2. コンパイルする
clang array_function_print.c -o array_function_print3. 実行する
./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;
}実行結果:
345return 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;
}実行結果:
100int 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つのまとまりとして扱えるようになり、配列や関数と組み合わせたプログラムを書きやすくなります。


