5 ポインター

5.1 コンピューターの構造

ポインターを学習する前に,ハードウェアーについて説明した.
図 4: コンピューターの基本構成
\includegraphics[keepaspectratio, scale=1.0]{figure/comp_5_equipments.eps}

5.2 メモリーとデータ

5.3 ポインターと演算子

ポインターに関係する演算子を表4にまとめておく.ただし,各変数は
	double x, *xp;

と宣言したとする.

表 4: 普通の変数とポインター変数に演算子を作用させた場合に取り出せる値.
演算子 通常の変数(x) ポインター変数(xp)
無し 格納されている値 格納されているアドレス x,xp
& 変数のアドレス   ポインター変数のアドレス &x,&xp
* コンパイルエラーのため不可 ポインターが示すアドレスに格納されている値 *xp

リスト2のプログラムをよく理解すること.アドレスとポイ ンターの関係や演算子の使い方を分からなくてはならない.

4行
整数型のポインターpを宣言している.pに整数型のデータの先頭 アドレスを格納する.
5行
整数型の変数 i を宣言し, $ (11223344)_{16}$を代入している.
7行
変数 i の先頭アドレスをアドレス演算子 &により取り出し,ポインター p に代入している.
9行
整数変数 i の先頭アドレスを変換指定子 %p により表示している.
10行
ポインター p の先頭アドレスを変換指定子 %p により表示している.
12行
整数変数 i の値を16進数表示の変換指定子 %0x により表示している.
13行
ポインター p の値を16進数表示の変換指定子 %0x により表示してい る.ただし,ポインターはアドレスなので,強制型変換(キャスト)により, 符号なし整数にしている.
15行
ポインターが指し示すアドレスに格納されているデータを表示している.

   1 #include <stdio.h>
   2 
   3 int main(void){
   4   int *p;
   5   int i=0x11223344;
   6 
   7   p=&i;
   8 
   9   printf("address i %p\n", &i);
  10   printf("address p %p\n", &p);
  11 
  12   printf("value i %0x\n", i);
  13   printf("value p %0x\n", (unsigned int)p);
  14 
  15   printf("value *p %0x\n", *p);
  16 
  17   return 0;
  18 }
\fbox{実行結果}
	address i 0xbffff6b0
	address p 0xbffff6b4
	value i 11223344
	value p bffff6b0
	value *p 11223344
この実行結果から,メモリーは図5のようになっていること が分かる.
図 5: リスト2のプログラム実行後のメモリーの内容
\includegraphics[keepaspectratio, scale=1.0]{figure/pointer_in_memory.eps}

5.4 ポインターの演算

ポインターは,整数型の値の和と差の演算ができる.しかし,積と商の演算はできない. ポインターの和や差の演算には,どういう意味があるのだろうか? リスト 3がそれに対する答えである.ポインターの演算--整数の加算 と減算--は,データの型のバイト数分,ポインターがシフト(移動)する.プログラムの 実行結果から分かるように, -4pt となっている.

ポインターに加算される整数は,ポインターが指し示すデータの移動量を表す.ひとつの アドレスには1バイトのデータが格納できる.そして,文字型のデータでは1バイト,整数 型では4バイト,実数型では8バイトのメモリーである.これが,型に依存して,アドレス の変化の仕方が異なった理由である.

   1 #include <stdio.h>
   2 
   3 int main(void)
   4 {
   5   char *cp;
   6   int *ip;
   7   double *dp;
   8   int i;
   9 
  10   for(i=0; i<4; i++){
  11     printf("%d %p\t%p\t%p\n",i, cp+i, ip+i, dp+i);
  12   }
  13 
  14   return 0;
  15 }
\fbox{実行結果}
0 0xbff0eb9c    0xbff0eb08      0x8048416
1 0xbff0eb9d    0xbff0eb0c      0x804841e
2 0xbff0eb9e    0xbff0eb10      0x8048426
3 0xbff0eb9f    0xbff0eb14      0x804842e

5.5 関数の引数にポインターを使う

5.5.1 参照渡しと値渡しの違い

関数呼出しの時,次のふたつの方法で値--処理すべきデータ--を渡すことができる.

参照渡しを使うと,グローバル変数を使わないで複数の計算結果を呼出元へ知らせること ができる.リスト4の関数cal()は,和と差,積,商を 一度に計算し,参照渡しを使い4つの値を一度に呼出元へ知らせている.実際には,呼出し元 から指定されたアドレスに,呼び出された関数cal()が計算結果を書き込んでいるの である.

   1 #include <stdio.h>
   2 
   3 void cal(int *wa, int *sa, int *seki, int *sho, int a, int b);
   4 
   5 //----------------------------------------------------------
   6 int main(void){
   7   int add, sub, mul, div;
   8 
   9   cal(&add, &sub, &mul, &div, 33, 3);
  10   printf("add = %d\n", add);
  11   printf("sub = %d\n", sub);
  12   printf("mul = %d\n", mul);
  13   printf("div = %d\n", div);
  14 
  15   return 0;
  16 }
  17 
  18 //----------------------------------------------------------
  19 void cal(int *wa, int *sa, int *seki, int *sho, int a, int b){
  20 
  21   *wa = a+b;
  22   *sa = a-b;
  23   *seki = a*b;
  24   *sho = a/b;
  25 }


\fbox{実行結果}
add = 36
sub = 30
mul = 99
div = 11

5.5.2 配列をユーザー定義関数に渡す方法

関数の引数に配列名を使う場合,参照渡しとなる.配列名は配列の先頭アドレスを表すポ インターとなっているからである.すなわち,配列名という変数(のようなも の)には,その配列の先頭アドレスが格納されている.その配列名--アドレスの値--を 渡すのであるから,参照渡しである.

リスト5に配列を関数に渡す例を示す.この例を見て分かるように,配列を 渡す場合は次のようにする.

リスト5の関数reverse()は,配列に格納されている順序を逆に する関数である.

   1 #include <stdio.h>
   2 void reverse(int n, int a[]);
   3 
   4 //--------------------------------------------
   5 int main(void){
   6   int hoge[3]={1,2,3};
   7 
   8   printf("hoge=\t%d\t%d\t%d\n",hoge[0],hoge[1],hoge[2]);
   9   reverse(3, hoge);
  10   printf("hoge=\t%d\t%d\t%d\n",hoge[0],hoge[1],hoge[2]);
  11 
  12   return 0;
  13 }
  14 
  15 //-------------------------------------------
  16 void reverse(int n, int a[]){
  17   int i, i_max, temp;
  18 
  19   i_max=n/2;
  20 
  21   for(i=0; i<i_max; i++){
  22     temp=a[i];
  23     a[i]=a[n-1-i];
  24     a[n-1-i]=temp;
  25   }
  26 }


\fbox{実行結果}
hoge=   1       2       3
hoge=   3       2       1

ホームページ: Yamamoto's laboratory
著者: 山本昌志
Yamamoto Masashi
平成19年3月4日


no counter