ポインタ演算
ポインタの加算・減算・比較操作。配列走査に重要
概要
ポインタに対して、 加算や減算などの演算を行うことができます。
このポインタ演算は、 配列の走査や複雑なメモリ操作で極めて重要です。
ポインタの加算と減算
例1: ポインタ + 整数
#include <iostream>
int main() {
int arr[5] = {10, 20, 30, 40, 50};
int* ptr = arr; // arr の最初の要素を指す
std::cout << "*ptr: " << *ptr << std::endl; // 10
std::cout << "*(ptr+1): " << *(ptr + 1) << std::endl; // 20
std::cout << "*(ptr+2): " << *(ptr + 2) << std::endl; // 30
return 0;
}
*ptr: 10
*(ptr+1): 20
*(ptr+2): 30
重要:ptr + 1は
「ptr から1個先」を意味します。
メモリ上ではsizeof(int)バイト先になります。
例2: ポインタの 加減演算
#include <iostream>
int main() {
int arr[5] = {1, 2, 3, 4, 5};
int* ptr = &arr[2]; // arr[2] を指す
std::cout << *(ptr - 1) << std::endl; // arr[1] = 2
std::cout << *ptr << std::endl; // arr[2] = 3
std::cout << *(ptr + 1) << std::endl; // arr[3] = 4
ptr++; // ポインタを次の要素に移動
std::cout << *ptr << std::endl; // arr[3] = 4
ptr--; // ポインタを前の要素に戻す
std::cout << *ptr << std::endl; // arr[2] = 3
return 0;
}
2
3
4
4
3
ポインタの比較
例:配列の要素を比較
#include <iostream>
int main() {
int arr[5] = {10, 20, 30, 40, 50};
int* ptr1 = &arr[1];
int* ptr2 = &arr[3];
std::cout << (ptr1 < ptr2) << std::endl; // 1 (true)
std::cout << (ptr1 > ptr2) << std::endl; // 0 (false)
std::cout << (ptr1 == ptr2) << std::endl; // 0 (false)
return 0;
}
1
0
0
ポインタ演算の実践例
例1: ポインタを使った配列の走査
#include <iostream>
int main() {
int arr[5] = {10, 20, 30, 40, 50};
int* ptr = arr;
// ポインタで配列を走査
for (int i = 0; i < 5; i++) {
std::cout << *ptr << " ";
ptr++; // 次の要素に移動
}
std::cout << std::endl;
return 0;
}
10 20 30 40 50
例2: ポインタで反転
#include <iostream>
int main() {
int arr[5] = {1, 2, 3, 4, 5};
int* start = arr;
int* end = arr + 4; // 最後の要素
while (start < end) {
// 入れ替え
int temp = *start;
*start = *end;
*end = temp;
start++;
end--;
}
// 表示
for (int i = 0; i < 5; i++) {
std::cout << arr[i] << " ";
}
std::cout << std::endl;
return 0;
}
5 4 3 2 1
例3: ポインタで文字列を処理
#include <iostream>
#include <cstring>
int main() {
const char* str = "Hello";
// ポインタを使って各文字にアクセス
for (const char* p = str; *p != '\0'; p++) {
std::cout << *p << " ";
}
std::cout << std::endl;
return 0;
}
H e l l o
ポインタの差分
2つのポインタの間の距離を計算できます。
#include <iostream>
int main() {
int arr[5] = {10, 20, 30, 40, 50};
int* ptr1 = &arr[1];
int* ptr2 = &arr[4];
std::ptrdiff_t diff = ptr2 - ptr1; // 距離を計算
std::cout << "距離: " << diff << std::endl; // 3
return 0;
}
距離: 3
ポインタと効率性
ポインタ演算はメモリアクセスが効率的です。
例:2つの方法の比較
#include <iostream>
int main() {
int arr[5] = {1, 2, 3, 4, 5};
// 方法1:インデックスアクセス
for (int i = 0; i < 5; i++) {
std::cout << arr[i] << " ";
}
std::cout << std::endl;
// 方法2:ポインタアクセス(若干高速)
for (int* p = arr; p < arr + 5; p++) {
std::cout << *p << " ";
}
std::cout << std::endl;
return 0;
}
1 2 3 4 5
1 2 3 4 5
ポインタと異なる型
#include <iostream>
int main() {
double arr[3] = {1.5, 2.5, 3.5};
double* ptr = arr;
// ptr + 1 は double 4 バイト先
std::cout << *ptr << std::endl; // 1.5
std::cout << *(ptr + 1) << std::endl; // 2.5
std::cout << *(ptr + 2) << std::endl; // 3.5
return 0;
}
1.5
2.5
3.5
ポインタ演算はデータ型のサイズを自動的に考慮します。
ポイント
- ポインタ + n で、データ型のサイズを掛けた先の位置
- ++/-- でポインタを次・前の要素に移動
- ポインタの比較でメモリ上の位置を判定
- ポインタの差分で要素数を計算
- 型のサイズが自動計算されるため、直感的
よくある誤り
誤り1: 配列の範囲を超える
int arr[5] = {1, 2, 3, 4, 5};
int* ptr = arr + 10; // 危険!: 範囲外
std::cout << *ptr << std::endl; // 未定義動作
誤り2: 初期化されていないポインタで演算
int* ptr; // 初期化されていない
ptr++; // 危険!: ゴミ値
誤り3: 異なる配列のポインタを比較
int arr1[5], arr2[5];
if (arr1 < arr2) { // メモリ上の位置の比較になる
// ...
}
やってみよう
練習1: ポインタを使って配列をコピー。
練習2: ポインタを使って配列を反転。
練習3: 文字列(C形式)をポインタで処理。
チャレンジ: ポインタを使ったバイナリサーチの実装。
まとめ
- ポインタ演算で配列を効率的に走査
- データ型に応じた自動計算が便利
- 範囲外アクセスに注意
- C++の重要なテクニック