定番の例:値の入れ替え(Swap)
CoddyのCジャーニー「Logic & Flow」セクションの一部 — レッスン 28/63。
swap関数は、C言語プログラミングにおいてなぜポインタが不可欠なのかを示す最も有名な例の一つです。目標は単純です。2つの変数の値を入れ替える関数を作成することです。しかし、この一見単純なタスクは、値渡し(pass-by-value)の根本的な制限を明らかにします。
通常の値渡し(pass-by-value)を使用して2つの変数を入れ替えようとした場合に何が起こるか考えてみましょう:
void badSwap(int a, int b) {
int temp = a;
a = b;
b = temp;
// これはコピーを入れ替えるだけで、元の変数は入れ替えません!
}このアプローチは、関数が値のコピーのみを受け取るため、失敗します。呼び出し元の関数内の元の変数は変更されないままです。
解決策では、代わりに変数へのポインタを渡す必要があります:
void swap(int *a, int *b) {
int temp = *a; // アドレスaの値を格納する
*a = *b; // アドレスbの値をアドレスaに入れる
*b = temp; // 格納された値をアドレスbに入れる
}変数のアドレスを渡し、間接参照演算子を使用することで、関数は元の変数の値を直接変更することができます。これにより、swap関数は、値渡し(pass-by-value)では到底対応できないタスクを達成するために、いつ、なぜポインタが必要なのかを示す最適な例となっています。
チャレンジ
簡単ポインタを使用して、古典的な入れ替え(swap)関数を実装し、その動作を確認するC言語プログラムを作成してください。プログラムは以下の要件を満たす必要があります:
- 2つの整数のポインタをパラメータとして受け取る、
swapという名前の関数を作成します。 swap関数内で、一時変数を使用して、2つのポインタが指すメモリ・アドレスにある値を入れ替えます。main関数内で、ユーザー入力から2つの整数を読み取ります。- 元の値を次の形式で出力します:
Before swap: a = [value], b = [value] swap関数を呼び出し、アドレス演算子を使用して両方の変数のアドレスを渡します。- 関数呼び出しの後、入れ替えられた値を次の形式で出力します:
After swap: a = [value], b = [value]
出力結果は、関数が元の変数の値を正常に入れ替えたことを示す必要があります:
Before swap: a = [first_input], b = [second_input]
After swap: a = [second_input], b = [first_input]この課題は、なぜ入れ替え操作にポインタが不可欠であるかを示しています。値を永続的に入れ替えるには、関数が元の変数のメモリ位置にアクセスする必要があり、これは値渡し(pass-by-value)では不可能です。
チートシート
swap関数は、C言語においてポインタが不可欠である理由を示しています。値渡しでは、関数はコピーしか受け取らないため、元の変数を入れ替えることはできません:
void badSwap(int a, int b) {
int temp = a;
a = b;
b = temp;
// これはコピーを入れ替えるだけで、元の変数は入れ替えません!
}正しいアプローチでは、ポインタを使用して元の変数にアクセスし、変更します:
void swap(int *a, int *b) {
int temp = *a; // アドレスaの値を保存する
*a = *b; // アドレスbの値をアドレスaに入れる
*b = temp; // 保存された値をアドレスbに入れる
}アドレスを渡し、間接参照演算子(*)を使用することで、関数は元の変数の値を直接変更できます。
自分で試してみよう
#include <stdio.h>
// TODO: ここにswap関数を記述してください
int main() {
int a, b;
// 入力を読み込む
scanf("%d", &a);
scanf("%d", &b);
// 元の値を表示する
printf("Before swap: a = %d, b = %d\n", a, b);
// TODO: ここでswap関数を呼び出してください
// 入れ替え後の値を表示する
printf("After swap: a = %d, b = %d\n", a, b);
return 0;
}このレッスンには短いクイズがあります。レッスンを始めて解答し、進捗を記録しましょう。