C言語 ポインタ

C言語

ポインタ変数

ポインタ変数は、アドレスを保存するための変数です。

アドレスを保存するための変数と聞いてもピンとこないかもしれません。

まず、変数とは、どのようなものかについて説明します。

変数は、データ(値)を入れる箱のようなものです。

この箱を作るには、箱の種類と名前が必要になります。箱の種類のことを型といい、名前を変数名と呼びます。

型と変数名の宣言によって実行プログラムが生成される時に変数のメモリ領域が確保され、その場所を示すアドレスが割り当てられます。(自動変数は除きます。)

つまり、変数には、必ずその変数の実体があり、その実体の場所を表すアドレスが存在します。

このアドレスを保存する変数としてポインタ変数があります。

ポインタ変数の書き方

ポインタ変数の宣言は、変数の宣言のように型を指定してポインタ変数名を書くのですが、通常の変数と異なるのは、ポインタ変数名の前にアスタリスクを付けることです。これにより指定した型のポインタ変数として認識されます。

 *ポインタ変数名

ポインタ変数に変数のアドレス値を代入する場合、アドレス演算子&を使って記述します。

ポインタ変数名 = &変数名

右辺の変数のアドレス値が左辺のポインタ変数に代入されます。

このとき、右辺の変数と左辺のポインタ変数の型は同じである必要があります。

ポインタ変数の例

ポインタ変数のサンプルプログラムを記述します。

long型(4バイト)変数aと、long型のポインタ変数lpを宣言します。

変数aには16進数で12345678という値を代入し、ポインタ変数lpには変数aのアドレス値を代入しています。

#include <stdio.h>

main()
{
    long a;
    long *lp;

    a  = 0x12345678;
    lp = &a;

    printf(" a=%lx  a  address=%p\n",a,&a);
    printf("lp=%p  lp address=%p  lp value=%lx\n",lp,&lp,*lp);
    printf("end\n");
}
C:\prog>pointer_test
 a=12345678  a  address=00F3FC24
lp=00F3FC24  lp address=00F3FC20  lp value=12345678
end

プログラムでは、変数aの値とアドレス値、ポインタ変数lpの値とアドレス値、ポインタ変数の値が指し示す先の値を出力しています。

それぞれの関係を表すと次の図のようになります。

ポインタ変数も変数のひとつなので、lp自身のアドレスを参照するとF3FC20というプログラムで割り当てられたアドレス値が返ってきます。

lpの箱の中には、変数aのアドレス値(この例では、F3FC24)が保存されています。

また、ポインタ変数は、ポインタ変数名の前に間接演算子*を付けることで、保存しているアドレス値の中の値を参照することができます。

この例では、*lpとすると変数aに保存されているデータ0x12345678を参照できるということになります。

ポインタでのアドレス制御

組み込みプログラムのお話を少ししたいと思います。

組み込みプログラムでは、ポインタを使って次のような書き方をします。(実際のプログラムでは記号定数で置き換えています。)

*(volatile unsigned char *)0x300000 = 1;

組み込みシステムでは、アドレスの先にセンサーやアクチュエータ、LEDなど様々なデバイスが接続されます。また、周辺機能の設定をするレジスタもアドレスに割り付けられ、プログラムは、そのアドレスに直接アクセスして設定を行います。

C言語では、ポインタを使ってアドレスを直接記述、操作できるので、デバイスやレジスタ制御の多い組み込みシステムを記述するプログラムに対してC言語は、使い勝手の良い言語といえるのではないかと思います。

ポインタ変数でできる演算

ポインタ変数は、次の演算をすることができます。

ポインタ変数でできる演算
  • インクリメント
  • デクリメント
  • 比較演算
  • 加算
  • 減算

ポインタ変数の演算例を示します。

#include <stdio.h>

main()
{
    short a[5] = {0,1,2,3,4};
    short *wp,*wp2;

    wp = a;
    wp2 = a;
    wp2 += 2;

    printf(" a =%p  a  address=%p\n",a,&a);
    printf("wp =%p  wp  address=%p  wp  value=%lx\n",wp,&wp,*wp);
    printf("wp2=%p  wp2 address=%p  wp2 value=%lx\n",wp2,&wp2,*wp2);
    printf("end\n");
}
C:\prog>pointer_test2
 a  =0056FBC8       a  address=0056FBC8
wp  =0056FBC8      wp  address=0056FBC0  wp  value=0
wp2 =0056FBCC      wp2 address=0056FBC4  wp2 value=2
end

short型で要素数5の配列aに0から4までの値を初期値として代入しています。

short型のポインタ変数wp、及び、wp2には、配列aの先頭アドレスを代入しています。

wp2は、その後、2を加算しています。

ここで重要な点は、ポインタ変数の加算は、単純にその値を加算するわけではないということです。

ポインタ変数の加算、減算は、

(ポインタ変数の型の大きさ)×(加減算値)

となります。

この例では、wp2+2しているので、short型の大きさ(2バイト)を2だけ加算するということになり、アドレスとしては、4加算した値、a[2]のアドレスとなります。

ポインタ変数の引数

引数にポインタ変数を使うことで、戻り値を使わずにデータのやり取りができます。これにより、出力値を引数で受け取ることができます。

また、戻り値によるデータの受け取りは1つのデータのみしかできませんが、ポインタ変数を引数に使うことで複数のデータを受け取ることが可能となります。

引数にポインタ変数を使った例を示します。

#include <stdio.h>int add1(int x,int y);
void add1_p(int x,int y,int *p);

main()
{
    int a,b,ans,ans_p;
    a = 1;
    b = 2;

    ans = add1(a,b);
    add1_p(a,b,&ans_p);
    printf("ans   = %d\n",ans);
    printf("ans_p = %d\n",ans_p);    
    printf("end\n");
}

int add1(int x,int y)
{
    int p;
    p = x + y;
    return(p);
}

void add1_p(int x,int y,int *p)
{
    *p = x + y;
}
C:\prog>add_test
ans     = 3
ans_p = 3
end

この例では、和を計算する関数として、戻り値で結果を返すadd1とポインタ変数を引数として用いてそのポインタ変数に結果を返すadd1_pを定義しています。計算結果はどちらも同じになりますが、プログラムをどう作るか、設計によって実装が変わってくる例となっています。

ここでは、変数に対するポインタの説明でしたが、関数に対してもポインタを扱うことができます。関数へのポインタは、こちらでまとめていますので、よかったらみてみてください。

C言語 関数ポインタ
C言語の関数ポインタについてまとめます。

コメント

タイトルとURLをコピーしました