関数で値を書き換える
関数の中で書き換えても戻らない
前回、scanf は番地を受け取るから呼び出し元を書き換えられる、という話をしました。同じことを、自分で書く関数でもできます。
まず、できない書き方から見ます。
void add_bonus(int score) {
score = score + 5; // 写しを書き換えているだけ
}
int main(void) {
int score = 80;
add_bonus(score);
printf("%d\n", score); // 80 のまま
}add_bonus が受け取る score は、呼び出し元とは別の変数です。名前が同じでも中身は写しなので、関数から抜けた瞬間に捨てられます。
番地を渡せば書き換えられる
引数の型をポインタにして、呼び出すときに & を付けます。
void add_bonus(int *score) {
*score = *score + 5; // 指している先を書き換える
}
int main(void) {
int score = 80;
add_bonus(&score);
printf("%d\n", score); // 85 になる
}関数の中では score はポインタなので、値を触るときは必ず * を付けます。score = score + 5; と書くとポインタの番地のほうを動かしてしまうので、コンパイラに叱られるか、書いた本人の意図と違う動きになります。
この渡し方を 参照渡し と呼びます。正確に言えば C にあるのは値渡しだけで、番地という値を渡すことで参照渡しの効果を作っている、という理解が正しい形です。
結果を 2 つ以上返したいとき
return で返せる値は 1 つだけです。ところが実際には、合計と最高点を一度に知りたい、といった場面がよくあります。ポインタの引数を使えば、必要な数だけ結果を持ち帰れます。
void swap_score(int *a, int *b) {
int tmp = *a;
*a = *b;
*b = tmp;
}入れ替えは、片方を先に上書きすると元の値が消えるので、一時変数 tmp に逃がしてから交換します。この 3 行の型は、これから先どの言語でも出てくる基本形です。
呼び出し側が & を付け忘れると、int を int * の引数に渡すことになるので、コンパイラが型の食い違いを教えてくれます。前回の scanf と違って気づきやすい部類のミスなので、素直に直してください。
では、2 人の点数を入れ替える関数を書いてみましょう。
要件
- 点数を2つ読み込む
- void swap_score(int *a, int *b) を定義して、指している先の値を入れ替える
- 入れ替える前を 「入替え前は80点と95点です」 の形で表示する
- 入れ替えたあとを 「入替え後は95点と80点です」 の形で表示する
入出力例
main("80 95") → "入替え前は80点と95点です
入替え後は95点と80点です"
main("60", "100") → "入替え前は60点と100点です
入替え後は100点と60点です"
main("77 77") → "入替え前は77点と77点です
入替え後は77点と77点です"ヒント
編集 LuaGate編集部