10.ポインタ

10-11. ポインタ配列

◇ポインタ配列

前も、少し触れましたが今回、徹底的にポインタ配列を検証してみます。

#include<stdio.h>

int main()
{
  int i;
  char *p_str[4]={"あいうえお","ABC",
                    "いろはにほへと","XYZ"};
  for(i=0;i<4;i++){
    printf("&p_str[%d] = %p ",i,&p_str[i]);
    printf("p_str[%d] = %p String = %s\n",i,p_str[i],p_str[i]);
  }
  return 0;
}

/* 結果1
&p_str[0] = 0064FDF4 p_str[0] = 0040A138 String = あいうえお
&p_str[1] = 0064FDF8 p_str[1] = 0040A143 String = ABC
&p_str[2] = 0064FDFC p_str[2] = 0040A147 String = いろはにほへと
&p_str[3] = 0064FE00 p_str[3] = 0040A156 String = XYZ
*/

p_str[4]
+——–+ +————–+
64FDF4番地 | 40A138 | —> 40A138番地 | “あいうえお” |
+——–+ +——-+——+
64FDF8番地 | 40A143 | —> 40A143番地 | “ABC” |
+——–+ +——-+———-+
64FDFC番地 | 40A147 | —> 40A147番地 | “いろはにほへと” |
+——–+ +——-+———-+
64FE00番地 | 40A156 | —> 40A156番地 | “XYZ” |
+——–+ +——-+

図に示すとこのようになります。
ポインタ配列全てで50バイト消費しています。
(文字列:34バイト ポインタ16バイト)

これが配列だった場合

#include<stdio.h>

int main()
{
  int i;
  char str[4][15]={"あいうえお","ABC",
                    "いろはにほへと","XYZ"};
  for(i=0;i<4;i++){
    printf("str[%d] = %p String = %s\n",i,str[i],str[i]);
  }
    printf("%d",sizeof(str));
  return 0;
}

/*
str[0] = 0064FDC8 String = あいうえお
str[1] = 0064FDD7 String = ABC
str[2] = 0064FDE6 String = いろはにほへと
str[3] = 0064FDF5 String = XYZ
60
*/

str[4]
+——————+
64FDC8番地 | “あいうえお” |
+——————+
64FDD7番地 | “ABC” |
+——————+
64FDE6番地 | “いろはにほへと” |
+——————+
64FEF5番地 | “XYZ” |
+——————+

このように、ポインタの分が必要無い代わりに各行を同じ長さにする必要があり、結果無駄な領域が発生して60バイト消費しています。

以上、構造上の違いにより単純に2次元配列を『ポインタのポインタ』に代入できないことがわかります。
(ポインタのポインタとは **point などを言います)
つまり、2次元配列を間接アクセス演算子を使って**strのようにアクセスはできても、**point などポインタのポインタとして宣言されているものには代入できないのです。

では、どうしてもこの前の2次元配列をポインタでアクセスしたい。
また、この配列を他の関数からアクセスさせたい。
そんなときはどうしましょう。