関数は C 言語のなかでも最も重要な概念のひとつです。数学の関数と同じく、ある値(の集合)を引数として、何らかの処理をし、その処理に応じて値を返します。関数にも変数と同じように、返す値によって型があり、宣言をする必要があります。関数を作るときは、引数の型や返す値、中で行われる処理、必要があれば保証しない動作などについてのコメントを書いてください。
関数を使うことで、処理のひとまとまりを分割することができるので、コードの構造がわかりやすくなります。以下に int 型の変数を引数とし、その二乗を返す関数の例を挙げます。
#include <stdio.h>
/* 関数の宣言をまとめて最初に書きます。*/
int square(int); /* ここは ; が必要です。*/
/* 関数の動作をここで宣言します。
その前にコメントを書きましょう。*/
/* この関数は、int 型を引数にとり、
その値の二乗を int 型で返します。
引数が int 型以外での動作は保証しません。*/
int square(int x)
{
/* 関数の中で使う変数の宣言をします。*/
int y;
/* 関数の中で行われる処理。*/
y = x * x;
/* y の値を、この関数の値として返します。*/
return y;
}
int main(void)
{
int a, b;
scanf("%d", &a);
b = square(a);
printf("%d * %d = %d
", a, a, b);
return 0;
}
処理が長くなったり、同じ処理を何回も使うとき、関数を使うと便利になります。
関数の中での変数はその中でのみ有効です。変数の値を使いたい場合は、引数として渡すようにしてください。
#include <stdio.h>
void func(void)
{
int a;
/* 変数 a の値が初期化されていないので
なにが表示されるかわかりません。*/
printf("%d
", a);
a = 1;
/* 1 が表示されます。*/
printf("%d
", a);
}
int main(void)
{
int a = 0;
/* 0 が表示されます。*/
printf("%d
", a);
func();
/* 0 が表示されます。*/
printf("%d
", a);
return 0;
}
練習問題: 最大公約数(gcd)と最小公倍数(lcm)を求める関数をつくり、それを使ったプログラムを書いてください。
同じ型の変数をたくさん作りたいときに、配列を使うと便利な場合があります。たとえば、int 型の五つの値を標準入力(キーボード)から入力し、それらの合計、平均(ave = <data>)、分散(s = <(data - <data>)2> = <data2> - <data>2)を求めるプログラムを示します。ここでは配列を使っていません。
#include <stdio.h>
int main(void)
{
int data0, data1, data2, data3, data4;
int sum;
double ave, s;
/* データの入力 */
printf("data0 = ");
scanf("%d", &data0);
printf("data1 = ");
scanf("%d", &data1);
printf("data2 = ");
scanf("%d", &data2);
printf("data3 = ");
scanf("%d", &data3);
printf("data4 = ");
scanf("%d", &data4);
/* 合計の算出 */
sum = data0 + data1 + data2 + data3 + data4;
/* 平均の算出 */
ave = sum / 5.;
/* 分散の算出 */
s = (data0 - ave) * (data0 - ave);
s += (data1 - ave) * (data1 - ave);
s += (data2 - ave) * (data2 - ave);
s += (data3 - ave) * (data3 - ave);
s += (data4 - ave) * (data4 - ave);
s /= 5;
/* 結果の表示 */
printf("Sum: %d
", sum);
printf("Average: %f
", ave);
printf("Variance: %f
", s);
return 0;
}
これを配列を使って書くとずっと簡単になります。
#include <stdio.h>
int main(void)
{
int data[5]; /* data という名前の配列を 5 個作ります。*/
int sum;
int i;
double ave, s;
/* データの入力 */
for (i = 0; i < 5; i++) {
printf("data[%d] = ", i);
scanf("%d", &data[i]);
}
/* 合計の算出 */
for (i = 0, sum = 0; i < 5; i++)
sum += data[i];
/* 平均の算出 */
ave = sum / 5.;
/* 分散の算出 */
for (i = 0, s = 0; i < 5; i++)
s += (data[i] - ave) * (data[i] - ave) / 5;
/* 結果の表示 */
printf("Sum: %d
", sum);
printf("Average: %f
", ave);
printf("Variance: %f
", s);
return 0;
}
上の例を見てわかるように、配列の宣言は普通の変数の宣言とほとんど同じです。配列には、オブジェクト名のあとに [] をつけます。配列の初期化は以下のようにして行います。
type identifier[number_of_array] = {value, value, ...};
実際の宣言ではたとえば以下のような記述をします。
float data[5] = {2.8, 4.9, 3.8, 1.2, 5.3};
上のように宣言したときに、data[0]
の値が 2.8 であり、data[5]
は存在しないことに注意してください。
というタイトルをつけてしまいましたが、実は C 言語には多次元配列はありません。C 言語では、多次元配列の代わり(?)に配列の配列を使います。宣言、初期化の例は以下の通りです。
int a[3][2] = {{2, 3, 5}, {4, 7, 1}};
ここまで執筆完了
ポインタとは、変数や関数に対して、それらを指し示すものという抽象的な概念です。ポインタも C 言語で重要な「型」のひとつです。つまり、ポインタ型の変数や、ポインタ型の値、ポインタ型の値を返す関数などがあります。ポインタ型の値とは、あるオブジェクトを指し示す「もの」のことで、多くの場合オブジェクトがあるメモリ上のアドレスが入っています。そのポインタ型の値を入れる変数をポインタ型の変数といいます。
ポインタ型は単独では存在できず、ある型からの派生型として存在します。つまり、int 型へのポインタ型や float 型へのポインタ型のようになるわけです。int 型へのポインタ型変数の宣言は下のような記述をします。
int *p;
*p がポインタなのではなく p がポインタ型の変数であることに注意してください。p の値はある int 型の変数を指すアドレスです。
ポインタの指すオブジェクトの実体を見るには * 演算子を使います。