#include <stdio.h>
// swap関数(ポインタを利用)
void swap(int *a, int *b) {
int temp = *a; // 一時変数に a の値を保存
*a = *b; // a に b の値を代入
*b = temp; // b に一時変数の値(元の a)を代入
}
int main() {
int x = 5, y = 10;
printf("交換前: x = %d, y = %d\n", x, y);
swap(&x, &y);
printf("交換後: x = %d, y = %d\n", x, y);
return 0;
}
実行結果
交換前: x = 5, y = 10
交換後: x = 10, y = 5
解説
temp に a の値を一時保存
a に b の値を代入
b に temp の値(元の a の値)を代入
メリット・デメリット
方法
メリット
デメリット
一時変数を使う
可読性が高く、バグが起きにくい
一時変数のメモリを消費する
この方法は、可読性が高く安全なため、一般的なCプログラムで最も推奨される方法です。
2.2 XOR演算を使ったswap関数
XOR(排他的論理和)演算を利用することで、一時変数を使わずに変数の値を入れ替えることができます。
コード例
#include <stdio.h>
// XORを用いたswap関数
void swap(int *a, int *b) {
if (a != b) { // 同じアドレスが渡された場合の防止策
*a = *a ^ *b;
*b = *a ^ *b;
*a = *a ^ *b;
}
}
int main() {
int x = 5, y = 10;
printf("交換前: x = %d, y = %d\n", x, y);
swap(&x, &y);
printf("交換後: x = %d, y = %d\n", x, y);
return 0;
}
C言語の関数では、デフォルトで「値渡し(call by value)」が行われる という特性があります。つまり、関数に渡した変数のコピーが作られるため、関数内部で変更しても元の変数には影響しません。
値渡しの例
#include <stdio.h>
// 値渡しのswap関数(間違った方法)
void swap(int a, int b) {
int temp = a;
a = b;
b = temp;
}
int main() {
int x = 5, y = 10;
printf("交換前: x = %d, y = %d\n", x, y);
swap(x, y);
printf("交換後: x = %d, y = %d\n", x, y);
return 0;
}
実行結果
交換前: x = 5, y = 10
交換後: x = 5, y = 10 ← 値が交換されていない!
解説
swap(x, y) を呼び出したとき、関数には x や y のコピー が渡されます。
したがって、関数内で a と b を交換しても、元の x と y は変わらない ままとなります。
この問題を解決するには、「参照渡し(call by reference)」 を利用する必要があります。
3.2 ポインタを使ったswap関数
ポインタを利用することで、関数に変数のアドレス を渡し、直接その値を変更することができます。
ポインタを利用したswap関数
#include <stdio.h>
// 正しいswap関数(ポインタを利用)
void swap(int *a, int *b) {
int temp = *a;
*a = *b;
*b = temp;
}
int main() {
int x = 5, y = 10;
printf("交換前: x = %d, y = %d\n", x, y);
swap(&x, &y); // アドレスを渡す
printf("交換後: x = %d, y = %d\n", x, y);
return 0;
}
#include <stdio.h>
// swap関数
void swap(int *a, int *b) {
int temp = *a;
*a = *b;
*b = temp;
}
// ヒープを調整する関数
void heapify(int arr[], int n, int i) {
int largest = i;
int left = 2 * i + 1;
int right = 2 * i + 2;
if (left < n && arr[left] > arr[largest])
largest = left;
if (right < n && arr[right] > arr[largest])
largest = right;
if (largest != i) {
swap(&arr[i], &arr[largest]);
heapify(arr, n, largest);
}
}
// ヒープソート関数
void heapSort(int arr[], int n) {
for (int i = n / 2 - 1; i >= 0; i--)
heapify(arr, n, i);
for (int i = n - 1; i > 0; i--) {
swap(&arr[0], &arr[i]);
heapify(arr, i, 0);
}
}
int main() {
int arr[] = {5, 2, 9, 1, 5, 6};
int size = sizeof(arr) / sizeof(arr[0]);
printf("ソート前の配列: ");
for (int i = 0; i < size; i++) {
printf("%d ", arr[i]);
}
printf("\n");
heapSort(arr, size);
printf("ソート後の配列: ");
for (int i = 0; i < size; i++) {
printf("%d ", arr[i]);
}
printf("\n");
return 0;
}