ポインタ算術は、C言語の基本的な特徴であり、メモリ作業を柔軟にする一方で、潜在的に危険でもあります。
ポインタ算術は、低レベル言語の特性から生じており、配列の操作や構造体データをメモリ内で直接処理するために設計されています。Cではすべてのポインタが、その指し示す型のサイズを「知っています」。
多くの開発者は、ポインタに1を加えるとアドレスがちょうど1バイト増えると思い込んでしまいます。しかし、実際にはsizeof(型)だけ増加します。異なるサイズの構造体等、異なるデータ型で作業をしていると、メモリを移動する際に簡単に間違えることがあります。また、void*を使ったポインタ算術は許可されておらず、これは一般的なエラーです。
すべてのポインタに対する算術操作は、対応する型のサイズを考慮しているため、配列との操作が最大限に効率的に行います。例えば:
#include <stdio.h> int arr[4] = {10, 20, 30, 40}; int *p = arr; printf("%d\n", *(p + 2)); // 30を出力します
ここで、(p + 2)はポインタを2 * sizeof(int)バイト進めており、単純に2バイト進むわけではありません。
主な特徴:
voidポインタに対してインクリメント/デクリメントの操作を行うことはできますか?
いいえ、Cの標準はvoidによる算術を禁止しています。最初にポインタを特定の型にキャストする必要があります、例えば(char)、その後に算術を行います。
void *vp = arr; char *cp = (char *)vp; cp++;
構造体や配列へのポインタに、配列のサイズを超える値を加えた場合はどうなりますか?
これは、有効なメモリ領域を超えてしまうことになります(未定義の動作)。Cは配列の境界をチェックしないため、責任はプログラマーにあります。
二つのポインタを直接加算することはできますか?
いいえ、ポインタの加算は禁止されており、意味を持ちません。配列に属する二つのポインタの引き算のみが許可されています。
若い開発者がint配列でポインタを使用して、型のサイズを忘れて固定バイト数でポインタを移動していました。
利点:
欠点:
経験豊富な開発者は常に(ptr + n)のような表現を使い、型のサイズに基づいてシフトをスケールするコンパイラを信頼します。
利点:
欠点: