ログイン
kid's world

たくさんの値を扱う

たくさんの値を扱う

さて,次がいよいよ本番である。大量の値を扱うのだ。たとえば,int型の値を100個保存したいと思ったとき,malloc関数で,int型100個ぶんのメモリ領域を確保すればよい。

int *p;
p=malloc(sizeof(int)*100);

しかし,この直後に,

*p=100;

とやっても,先頭の1個ぶんのメモリの内容が書き換わるだけで,せっかく確保した後の99個ぶんのメモリ領域は使われないままである。どうしたら残りの領域を使えるのだろうか。実はこのように書けばよい。

*p=100;
*(p+1)=127;
*(p+2)=1234;
...

今回はint型で100個の領域を確保したのだから,「*(p+99)」までである。このとき誤って,

*(p+100)=100;

と書いてしまっても,コンパイルはできる。しかし確保されていない領域に書き込んでしまうため,非常に危険である。このあたりは注意して使いたい。

ポインタ変数に対する加算・減算

先ほどの書き方に疑問を持たれた方はいないだろうか。pはint型を指すポインタ変数である。int型が1バイトならこれでいいが,普通は2バイトか4バイトだ。だから本当なら「*(p+1)」と書くのではなくて,「*(p+2)」とか「*(p+4)」と書くのではないだろうか。

実は,ポインタに対する加算や減算は,普通の変数に対する加算や減算と少し違う。ポインタは,「アドレス」と「型」を持っている。ポインタに対して1を加算・減算することは,アドレスを型のサイズだけ加算・減算することに相当するのだ。論より証拠である。List 6を見ていただきたい。

List 6: アドレスの増加の検証

#include <stdio.h>
#include <stdlib.h>

main()
{
  int *ip;
  float *fp;
  
  ip=malloc(sizeof(int)*2);
  if(ip==NULL) exit(1);
  
  fp=malloc(sizeof(float)*2);
  if(fp==NULL) exit(1);
  
  printf("ip:%p, ip+1:%p\n", ip, ip+1);
  printf("fp:%p, fp+1:%p\n", fp, fp+1);
  
  free(ip);
  free(fp);
}

このプログラムでは,ポインタを加算すると,アドレスがどのように増加するのかを検証するものである。int型とfloat型のポインタ変数にそれぞれ1足したとき,アドレスはどうなるかをよく見てみよう。筆者のPCでは,次のような結果となった。

ip:1420, ip+1:1422
fp:1428, fp+1:142C

これを見れば明らかなように,int型のためのポインタ変数はアドレスが2進み,float型のためのポインタ変数はアドレスが4進んでいる。ということは,List 7のような書き方もできるわけだ。ここでやっていることがわかれば,ほとんどポインタについてはわかったといってよいだろう。

List 7: 別の書き方

#include <stdio.h>
#include <stdlib.h>

main()
{
  int *p, *q;
  
  p=malloc(sizeof(int)*3);
  if(p==NULL) exit(1);
  
  q=p;
  
  *q=100;
  q++;
  *q=200;
  q++;
  *q=300;
  
  printf("%d,%d,%d\n",*p,*(p+1),*(p+2));
  
  free(p);
}

List 7では,まずint型のためのポインタ変数pとqを宣言している。次にint型3つぶんのメモリ領域を確保し,先頭アドレスをpに代入し,さらにqにも代入している。この時点で,pとqは同じアドレスを指している。そして,

*q=100;

として,いちばん最初の領域に100を書き込んでいる。これは今までと同じである。よく考えてほしいのは次だ。

q++;
*q=200;

なんと,ポインタ変数自身を書き換えているのだ。「++」は数値を1加算する演算子(インクリメント演算子)だが,ポインタ変数の場合は型のサイズだけ増加することになる。したがって,その次の領域に200が書き込まれるわけだ。これをイメージ的に書くと,Fig. 9のようになる。ポインタ変数qの指し示す先だけが,つぎつぎと飛んでいくようになるのだ。

Fig. 9: ポインタ変数をインクリメントする

/c/pointer-fig9.png

ポインタ変数pを動かさないでいるわけは,free関数を呼び出すときのためだ。free関数は,malloc関数が渡したアドレスを受け取らなければならないからだ。


配列」へ進む

広告


©Toshio Koide 1996-2007.

目次

リンクについて

リンクは御自由にどうぞ。

メール

mail.gif

広告