パソコン活用研究シリコンバレー(C、C++、の活用研究)

再び配列とポインタその2

前回の再び配列とポインタでは、配列とポインタについて少しつっこんでみました。
今回は、もう少し掘り下げてみましょう。

前回は、
Int a[4] = {1,2,3,4};
と配列で宣言すると、a は配列a[ ]の先頭アドレスを示し、
a[0] =*a, a[1]=*(a+1)
というように記述できるよ、ということを書きました。

こう書くと、なんだ、配列とポインタ変数はまったく同じもんじゃん、と思いたくなりますが、
厳密にいうと若干違います。

例えば
int a[4];
int *b;

の場合、 *b++, b++はOK. ですが、*a++, a++とするとコンパイルエラーがでるはずです。
あらやだな、何がチガウンジャという声が聞こえてきそうですが、ポインタ変数のb は変数であり
(ポインタ変数だからね)、a は定数だからです。
従って、b=6 はOK. cも整数変数とすれば、 c=a はOK.でも、a=5 は不可です。


更に、もうひとつ。
int a[4];
というように配列を宣言すると、メモリ上にa[0]からa[3]までの領域が確保されます。
int *b;
とポインタ変数を宣言した場合は、b の領域がメモリー上に確保され、*b に値が代入されると
*b のための領域が別途確保されます。すなわち*bの他にポインタ(b)のための領域がメモリ上に
あるということです。
ちょっと、プログラムでホントかどうか確認してみましょう。
ここでは、2次元配列とポインタ配列で比較してみました。

/* Coded by Tsuyoshi Kasai  for LSIC     */
/*  2次元配列とポインタ配列     */
#include <stdio.h>

char data[2][3] = {"Oh\0","K!\0"};
char *dt[2] ={"Oh\0","K!\0"};                  

main(){
int i;
printf("data:%d  data[0]:%d  data[1]:%d\n",data,data[0],data[1]);
for (i=0;i<2;i++) printf("%s",data[i]);
 
printf("\n\ndt:%d  dt[0]:%d  dt[1]:%d\n",dt,dt[0],dt[1]);
for (i=0;i<2;i++) printf("%s",dt[i]);
 }                 

実行結果をみてみましょう

C:\C>nijigen1
data:102 data[0]:102 data[1]:105           
OhK!

dt:108 dt[0]:112 dt[1]:116
OhK!
C:\C>

配列の方は data = data[0] = data[0][0]のアドレス=文字列”Oh”の先頭アドレス。
一方、ポインタ配列の方は、
dt= dt[0]のアドレス。 dt[0]=*dt[0]のアドレス=文字列”Oh”の先頭アドレス。

違いがわかりましたか。表にしてみましょう
配列では、data も data[0] も実際のデータの先頭(”O”)をさしているだけです。
一方、ポインタ配列では、実際のデータがある領域(アドレス112から)とは別個に、ポインタのポインタ
であるdt,ポインタのdt[0],dt[1]のための領域が確保されているのが、わかると思います。

アドレス メモリ上のデータ  
102(data[0][0]) O  <--data = data[0] =data[0][0]のアドレス
103(data[0][1]) h    
104 \0  
105 K  
106 !  
   
    (dt) 108 <--dt[0] のポインタ(アドレス)
108  (dt[0]) 112 <--*dt[0]のポインタ(アドレス)
110 (dt[1]) 116 <--*dt[1]のポインタ(アドレス)
112 O  
113 h  
114 \0  
116 K  
117 !  
     

このように、配列として宣言した場合と、ポインタ変数として宣言した場合で、若干相違点があります。
(上記のケースは、2次元配列とポインタ配列)
関数の引数として、配列やポインタ変数を渡そうとすると、この相違に注意しなくてはならないことが
発生します。この点については次回の配列とポインタその3でとりあげます。

TopPage