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

削除された内容 追加された内容
→‎配列ポインタに対する加算: このように、ポインタ型やアドレスに対する加算は、通常の加算とは意味が異なります。
→‎配列ポインタに対する加算: 二次元配列の場合を追記
36 行
 
== 配列ポインタに対する加算 ==
=== 一次元配列の場合 ===
 
配列aの配列ポインタそのものに *pa+1 などの計算をしても、
それは決して先頭アドレス値に+1をしたものを意味せず、 *pa+1 は<code>a[1]</code>を意味します。
67 行
 
 
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 );
 
}
115 行
 
どのみち、上記例のようなint型を用いたアドレス計算には、実用価値もありません。
 
=== 二次元配列の場合 ===
二次元配列のポインタに関する加算も可能であり、若干の相違点はありますが、一次元の場合と似たような処理が可能です。詳しくは、下記コードとその実行例とその解説をお読みください。
 
<syntaxhighlight lang=c>
#include <stdio.h>
 
int main(void) {
int a[3][2] = {
{2, 3},
{5, 7},
{11,13}
};
 
int k=0;
for (int i = 0; i < 2; i++){
printf("%d ", a[k][i]);
}
printf("\n");
 
int *pa = a[0]; // 一番右側の次元が省かれる。
 
printf("アドレスpaは %p \n", pa);
printf("アドレス&a[0][0]は %p \n", &a[0][0]);
printf("アドレス&a[0][1]は %p \n", &a[0][1]);
printf("\n");
printf("アドレスpaは %p \n", pa);
printf("アドレスpa+1は %p \n", pa+1);
 
printf("(&a[0]) +1の場合でも %p \n", (&a[0][0]) +1 );
 
}
</syntaxhighlight>
 
実行結果
<pre>
2 3
アドレスpaは 000000000022FE20
アドレス&a[0][0]は 000000000022FE20
アドレス&a[0][1]は 000000000022FE24
 
アドレスpaは 000000000022FE20
アドレスpa+1は 000000000022FE24
(&a[0]) +1の場合でも 000000000022FE24
</pre>
 
* 解説
注目すべきことは、
:<code>int a[3][2] </code>
のように二次元配列を宣言したにもかかわらず、
 
配列ポインタの代入の命令文では
:<code>int *pa = a[0]; </code>
のように次元がひとつ下がっていることです。
 
これは<code>a[0][0]</code>および<code>a[0][1]</code>といった、つまり<code>a[0][なにか]</code>グループの先頭配列という意味です。
なので、結果的にこの例の場合なら<code>a[0][0]</code>のアドレスに一致します。
 
三次元以上でも同様の処理が可能ですが、似た説明の繰り返しになるので、本ページでは説明を省略します。(おそらく本wikibooks『C言語』教科書全体でも説明が省略されると思います。)
 
== 配列の要素数を求めるイデオム ==