Cプログラミング
 Computer >> コンピューター >  >> プログラミング >> Cプログラミング

C言語のポインタとは?基本概念をサンプルコード付きで解説


ポインタとは?

ポインタ(pointer)とは、別の変数のメモリアドレスを格納するための変数です。C言語ではポインタを使うことでメモリを直接操作でき、効率的なデータ処理や関数間でのデータ受け渡しが可能になります。

ポインタの基本構文は以下のとおりです。

pointer = &variable;

「&」はアドレス演算子と呼ばれ、変数の先頭アドレスを取得します。また、「*」は間接参照演算子(デリファレンス)であり、ポインタが指し示すアドレスに格納された値を取り出します。

C言語によるポインタのサンプルプログラム

次のプログラムでは、int型ポインタとchar型ポインタのそれぞれについて、データサイズ・アドレス・参照先の値を確認します。

#include<stdio.h>
void main(){
    // 変数とポインタの宣言
    int a = 2;
    int *p;
    // ポインタpに変数aのアドレスを代入
    p = &a;
    // int型ポインタでの確認
    printf("int型のサイズは %d バイトです\n", sizeof(int));           // 4
    printf("%d のアドレスは %d です\n", a, p);                        // アドレス値
    printf("%d の値は %d です\n", a, *p);                             // 2
    printf("%d の次のアドレス位置の値は %d です\n", a, *(p+1));       // (p+1)番地の不定値
    printf("%d の次のアドレス位置のアドレスは %d です\n", a, (p+1));  // アドレス値 + 4
    // ポインタをchar型へキャスト
    // a = 2 を2進数で表すと 00000000 00000000 00000000 00000010
    char *p0;
    p0 = (char*)p;
    // char型ポインタでの確認
    printf("char型のサイズは %d バイトです\n", sizeof(char));         // 1
    printf("%d のアドレスは %d です\n", a, p0);                       // アドレス値(p)
    printf("%d の値は %d です\n", a, *p0);                            // 値aの1バイト目 - 2
    printf("%d の次のアドレス位置の値は %d です\n", a, *(p0+1));      // 値aの2バイト目 - 0
    printf("%d の次のアドレス位置のアドレスは %d です\n", a, (p0+1)); // アドレス値(p) + 1
}

実行結果

上記のプログラムを実行すると、次のような結果が出力されます(アドレスの数値は実行環境によって異なります)。

int型のサイズは 4 バイトです
2 のアドレスは 6422028 です
2 の値は 2 です
2 の次のアドレス位置の値は 463824 です
2 の次のアドレス位置のアドレスは 6422032 です
char型のサイズは 1 バイトです
2 のアドレスは 6422028 です
2 の値は 2 です
2 の次のアドレス位置の値は 0 です
2 の次のアドレス位置のアドレスは 6422029 です

実行結果のポイント解説

1. ポインタの加算は「型のサイズ」ぶんだけ進む

int型は4バイトのため、ポインタpを1つ進めると(p+1)、アドレスは4増加します(6422028 → 6422032)。一方、char型は1バイトなので、p0+1ではアドレスが1だけ増加します(6422028 → 6422029)。ポインタ演算では「指し示す型のサイズ」が基準になる点が重要です。

2. 型キャストで読み取る単位が変わる

(char*)p とキャストすると、同じアドレスを1バイト単位で読み取れるようになります。多くの環境(リトルエンディアン)では、int型の 2 は下位バイトから「02 00 00 00」の順で格納されるため、*p0 は 2、*(p0+1) は 0 となります。

3. 未初期化領域の参照には注意

*(p+1) の出力である 463824 は、変数aの隣にある未確保のメモリ領域に入っていた不定値(ゴミ値)です。意図しないメモリを参照すると予測不能な値が返るため、実務では範囲外アクセスに十分注意しましょう。

なお、本記事のコードは元資料に合わせて void main() を使用していますが、標準規格に準拠した形式としては int main(void) とし、最後に return 0; を返す書き方が推奨されます。

  1. C言語のシフト演算とは?左シフト・右シフト・補数の基本をわかりやすく解説

    問題 C言語を使用して、ある数値に対する左シフト・右シフト・補数(ビット反転)を求める簡単なプログラムを作成するには、どのようにすればよいのでしょうか。 解決方法 左シフト(<<) 変数の値を1ビットだけ左へシフトすると、その値は2倍になります。「a × 2」を計算したのと同じ結果です。 例:a = 10 の場合、a << 1 = 20 右シフト(>>) 変数の値を1ビットだけ右へシフトすると、その値は元の半分になります。「a ÷ 2」の整数除算と同じ結果です。 例:a = 10 の場合、a >> 1 = 5 サンプルプログラム 以下は、シ

  2. C言語のポインタ入門!宣言・初期化から配列アクセスの実例まで徹底解説

    ポインタ(pointer)とは、他の変数のメモリアドレスを格納するための変数です。C言語においてポインタは、メモリを直接操作したり、関数間でデータを効率的にやり取りしたりするために欠かせない重要な概念です。 ポインタの宣言・初期化とアクセス まず、次のような通常の整数変数の宣言を見てみましょう。 int qty = 179; 変数qtyには値「179」が格納されると同時に、メモリ上のどこかにその格納場所(アドレス)が割り当てられます。 ポインタの宣言 int *p; 「p」はポインタ変数であり、別の整数型(int)変数のアドレスを保持します。変数名の前にアスタリスク(*)を付けることで、「こ