「C言語/配列とポインタ」の版間の差分

削除された内容 追加された内容
Ef3 (トーク | 投稿記録)
→‎多次元配列と多次元配列へのポインター: 先頭要素へのポインターから配列の配列へのポインターに変更。
タグ: 2017年版ソースエディター
Ef3 (トーク | 投稿記録)
配列変数名は配列の先頭要素のアドレス。配列のアドレスを初期値とするには、配列へのポインタ型の変数である必要がある。混同しがち。
タグ: 2017年版ソースエディター
20 行
printf("\n");
 
int *pa = a; //* 配列名(この場合は「a」)は配列の先頭要素(int)のアドレスを示すので「&」をつけない
&a は配列のアドレスを表すのでその場合は、int (*)[10] が型となる。
printf("%d ", *(pa + 2)); //ポインターpaを使って配列aの要素を表示する。
33 ⟶ 34行目:
</pre>
 
一般に配列の先頭要素のアドレスを格納したポインター変数 pa では、 +0 によって配列の0項目。+1によって配列の1項目、+2によって配列の2項目、・・・を参照できます。
このため、上記のような<code *(pa + i)></code>というコードで、配列のそれぞれの要素を参照できます。
 
== 配列ポインタに対する加算 ==
=== 一次元配列の場合 ===
配列aの配列ポインタそのものに *pa+1 などの計算をしても、
それは決して先頭アドレス値に+1をしたものを意味せず、 *(pa + 1) は<code>a[1]</code>を意味します。
同様に *(pa + 2) は<code>a[2]</code>を意味します。
 
配列は必ず<code>a[i]</code>と<code>a[i+1]</code>とのアドレス間が等間隔なので、
もしコンパイラ開発者がこのような処理を実装しようとする際には、単に、配列の先頭要素のアドレスをコピーする際に一緒に配列のアドレス間隔もコピーするように実装すれば済みます。
 
なので、配列要素をひとつひとつコピーする方式と比べればコピー回数を大幅に減らせるので、プログラマーは配列の先頭要素のアドレスを示すポインタ配列のーを活用することで、要素数がとても多い配列の場合には高速化につながります。
 
なお、<code>(&a[0]) +1</code> を表示しても同様に <code>a[1]</code>を意味します。
61 ⟶ 63行目:
printf("\n");
 
int *pa = a; //* 配列名(この場合は「a」)は配列の先頭要素(int)のアドレスを示すので「&」をつけない
&a は配列のアドレスを表すのでその場合は、int (*)[5] が型となる。
 
printf("%d ", *(pa + 2)); //ポインターpaを使って配列aの要素を表示する。
82 ⟶ 85行目:
printf("\nどうしても整数計算的に+1したいなら\n", h +1 );
printf("int h = &a[0];によって %x \n", h +1 );
 
}
</syntaxhighlight>
106 ⟶ 108行目:
</pre>
 
 
では、どうしても先頭アドレス&a[0] たとえば 000000000022FE20 を整数計算的に+1したい場合(つまり単なる 000000000022FE21 のような数)、どうすればいいのでしょうか。答えは、単に int型の別変数を新規に<code>int h =&a[0];</code>で宣言し、そのhに+1を行えばいいだけです。
 
コンパイラによっては警告文が出ますが(たとえば gcc など)、しかし今回は意図通りの計算です。
 
ただし計算表示はできるものの、このようなint型を介したアドレス計算をコンパイラが非推奨にしており(なので警告文が出る)、
正式サポートはしていないので、データの欠損などの起こる可能性も考えられます。なので仕事などの本番では、int型を用いたアドレス計算は用いないほうが良いでしょう。
 
どのみち、上記例のようなint型を用いたアドレス計算には、実用価値もありません。
 
=== 二次元配列の場合 ===