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

削除された内容 追加された内容
Ef3 (トーク | 投稿記録)
タグ: 2017年版ソースエディター
Ef3 (トーク | 投稿記録)
{{See also|C言語/ポインタ#コラム:intにアドレス値を代入してはいけない!}}
タグ: 2017年版ソースエディター
57 行
 
== 配列ポインタに対する加算 ==
=== 一次元配列の場合 ===
配列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>を意味します。
 
このように、ポインタ型やアドレスに対する加算は、通常の加算とは意味が異なります。
 
;[https://paiza.io/projects/tkaTaxajFScWrdgyPa--aQ?language=python3 コード例]:<syntaxhighlight lang="C">
#include <stdio.h>
 
int main(void) {
int a[5] = {2, 3, 5, 7, 11};
 
for (int i = 0; i < 4; i++)
printf("%d ", a[i]); //配列aの要素を一覧表示する。
printf("\n");
 
int *pa = a; /* 配列名(この場合は「a」)は配列の先頭要素(int)のアドレスを示す。
&a は配列のアドレスを表すのでその場合は、int (*)[5] が型となる。*/
 
printf("%d ", *(pa + 2)); //ポインターpaを使って配列aの要素を表示する。
printf("\n");
 
printf("アドレスpaは %p \n", pa);
printf("アドレス&a[0]は %p \n", &a[0]);
printf("アドレス&a[1]は %p \n", &a[1]);
printf("アドレス&a[1]は %p \n", &a[2]);
printf("\n");
printf("アドレスpaは %p \n", pa);
printf("アドレスpa+1は %p \n", pa+1);
printf("アドレスpa+2は %p \n", pa+2);
 
printf("(&a[0]) +1の場合でも %p \n", (&a[0]) +1 );
printf("%%pでなく%%xの場合でも %x \n", (&a[0]) +1 );
 
int h = &a[0];
printf("\nどうしても整数計算的に+1したいなら\n", h +1 );
printf("int h = &a[0];によって %x \n", h +1 );
}
</syntaxhighlight>
;実行結果:<syntaxhighlight lang="text">
2 3 5 7
5
アドレスpaは 0x7ffccc95ac30
アドレス&a[0]は 0x7ffccc95ac30
アドレス&a[1]は 0x7ffccc95ac34
アドレス&a[1]は 0x7ffccc95ac38
 
アドレスpaは 0x7ffccc95ac30
アドレスpa+1は 0x7ffccc95ac34
アドレスpa+2は 0x7ffccc95ac38
(&a[0]) +1の場合でも 0x7ffccc95ac34
%pでなく%xの場合でも cc95ac34
 
どうしても整数計算的に+1したいなら
int h = &a[0];によって cc95ac31
</syntaxhighlight>
{{See also|C言語/ポインタ#コラム:intにアドレス値を代入してはいけない!}}