はじめに
私は初心者である。この備忘録を参考にされようとしている他の初心者の方は、ここに書かれていることを鵜呑みになさらぬようお願いしたい。何か間違いを見つけた方はコメント欄でご報告頂きたい。
関数の型と宣言
関数の型
関数の引数と戻り値を合わせて関数の型という。
下記の関数では引数がint
とint
で戻り値がint
だ。
int add (int x, int y) {...}
この書き方だと関数の型を宣言して本体を定義しているが、下記のように型だけを定義する書き方があるらしい。
int add (int x, int y); // 仮引数の名前は省くことができる
このようにして関数を宣言することを関数宣言と呼ぶ。
C言語では関数宣言をするのが基本だそうだ。関数定義の前に、まとめて書くのが慣習とのこと。
main
関数においてはもともと処理系が型を理解しているから宣言はしないらしい。
関数宣言の役割
Cのコンパイラは上から順にプログラムをみる。関数宣言はコンパイラに関数の型を教え、関数を呼び出すための正しい機械語コードを作るのに利用される。
呼び出される関数を先に定義しておくと関数宣言の役割もこなしてくれるが、関数の数が多くなってくるとそのような作業も面倒くさくなる。関数宣言に慣れよう。
2つの整数の和を求める関数add
と関数宣言の例
int add(int, int); // 関数宣言
int add(int x, int y) {
return x + y;
}
int main(void) {
int a, b;
a = 10;
b = 5;
printf("a + b = %d\n", add(a, b)); // a + b = 15が出力される
return 0;
}
自動変数と再帰呼び出し
自動変数
関数が呼び出されるときには、実引数の値が仮引数に代入される。仮引数は変数なので使用するにはメモリ領域がなければいけない。しかし、仮引数のメモリ領域というのは宣言した時に作られるているのではない。呼び出しの時に新しく作られ、関数から戻るときになくなっている。local variable
みたいなもんだろうな。
このような特徴を持つ関数の仮引数やif
文やwhile
文などのブロック内で宣言される変数を自動変数と呼ぶ。
再帰呼び出し
ハイ出てきましたこれ。再帰呼び出し。数学的なセンスがない私はとても苦手です。
int rsum(int);
int rsum(int n){
if (n==0)
return 0;
else
return n + rsum(n-1); // 自分の中で自分自身を呼び出す(再帰呼び出し)
}
int main(void){
int x;
x = rsum(4);
printf("%d\n", x);
return 0;
}
再帰的に定義されるものについては再帰呼び出しを使うと簡単にプログラムを書ける場合が多い。しかし、再帰呼び出しより繰り返しを用いた方が、大抵は実行速度が速くメモリ消費も少ないらしい。
再帰呼び出し嫌いの私は積極的に繰り返しを使おう。
レジスタ変数
int main(void){
register int i, j;
for (i=1; i<=9; i++) {
for (j = 1; j<=9; j++)
printf("%2d ", i*j);
printf("\n");
}
return 0;
}
1 2 3 4 5 6 7 8 9
2 4 6 8 10 12 14 16 18
3 6 9 12 15 18 21 24 27
4 8 12 16 20 24 28 32 36
5 10 15 20 25 30 35 40 45
6 12 18 24 30 36 42 48 54
7 14 21 28 35 42 49 56 63
8 16 24 32 40 48 56 64 72
9 18 27 36 45 54 63 72 81
register int i, j;
のようにregister
という予約語がついている変数をレジスタ変数と呼ぶ。レジスタ変数には処理系に、できるだけその変数へのアクセスを早くしてくれと伝える意味がある。
register
指定をしなくても、コンパイラは実行速度の速いコードを生成しようとする。これを最適化と呼ぶ。
レジスタ変数の制約
単項演算子の&
はレジスタ変数に適用できない。この演算子はよくscanf
の引数で使われる。これはアドレス演算子と言って、変数のアドレスを得る演算子だ。レジスタ変数の記憶領域としてプロセッサのレジスタが割り当てられることがあり、レジスタはメモリアドレスを持たないから演算ができない。
下記のようなコードが書けないということだ。
register int x;
scanf("%d", &x);
外部変数
自動変数は有効な範囲が限られている変数だった。外部変数はプログラム中のどこでも有効な変数だ。
関数の外で宣言すれば外部変数になる。
void add1 (void);
int x; // 宣言
void add1(void) {
printf("%d\n", x);
x++;
return;
}
int main(void){
x = 2;
add1();
printf("%d\n", x);
return 0;
} // 2と3が出力される
プログラム全域に渡って使うような情報は外部変数を使うと便利だ。
ただ、他ファイルからのアクセスを可能にするには外部変数を作るだけではいけない。まずコンパイルは、ファイルごとにされるから、関数宣言は各ファイルごとにするか、include
を使ってヘッダファイルを共有しなければならない。また、他ファイルからのアクセスを可能にするためのextern
宣言もしなければならない。
追記 extern
についてはこちらがわかりやすい。
今回の内容は富永和人氏の新しいC言語の教科書を参考に書き留めてます。