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

削除された内容 追加された内容
Ef3 (トーク | 投稿記録)
{{See also|C言語/ポインタ#コラム:intにアドレス値を代入してはいけない!}}
タグ: 2017年版ソースエディター
Ef3 (トーク | 投稿記録)
タグ: 2017年版ソースエディター
58 行
== 配列ポインタに対する加算 ==
{{See also|C言語/ポインタ#コラム: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][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][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>のアドレスに一致します。
 
その証拠として、<code>a[1][なにか]</code>グループ(二次元目が0でなく1です)の先頭配列のアドレスも同様の方法で代入できます。
 
<syntaxhighlight lang="C">
#include <stdio.h>
 
int main(void) {
int a[3][2] = {
{2, 3},
{5, 7},
{11,13}
};
 
int k=1; // 1に変更
for (int i = 0; i < 2; i++){
printf("%d ", a[k][i]);
}
printf("\n");
 
int *pa = a[1]; // a[1][なにか]グループに変更
 
printf("アドレスpaは %p \n", pa);
printf("アドレス&a[1][0]は %p \n", &a[1][0]);
printf("アドレス&a[1][1]は %p \n", &a[1][1]);
printf("\n");
printf("アドレスpaは %p \n", pa);
printf("アドレスpa+1は %p \n", pa+1);
 
printf("(&a[1][0]) +1の場合でも %p \n", (&a[1][0]) +1 );
 
}
</syntaxhighlight>
 
実行結果
<pre>
5 7
アドレスpaは 000000000022FE28
アドレス&a[1][0]は 000000000022FE28
アドレス&a[1][1]は 000000000022FE2C
 
アドレスpaは 000000000022FE28
アドレスpa+1は 000000000022FE2C
(&a[1][0]) +1の場合でも 000000000022FE2C
</pre>
 
 
なお、二次元以上の配列を <code>int *pa = a;</code> のように、<code>[ ]</code>をひとつもつけずに代入しようとすると、コンパイラから警告されます(MinGWで確認)。
 
==== 二次元目を変えてアクセスしたい場合 ====
ポインタを活用して二次元目以降を複数の<code>a[0][なにか]</code> と <code>a[1][なにか]</code>のように二次元目の値の違いを超えてポインタで扱いたい場合、単に<code>pa + 数 ;</code>の計算で足す数が1次元目の要素数-1をオーバーすれば、二次元目が位上げのように1上がるので、次の配列へのアクセスに移ります。0から数えるので、二次元目を+1してアクセスする場合は要素数-1です。
 
<syntaxhighlight lang="C">
#include <stdio.h>
 
int main(void) {
int a[3][2] = {
{332, 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)は %d \n", *(pa) );
printf("*(pa+2)は %d \n", *(pa+2) );
}
</syntaxhighlight>
 
実行結果
<pre>
332 3
*(pa)は 332
*(pa+2)は 5
</pre>
 
このように、単にポインタ変数 pa に足す数値を調整することで参照先配列の二次元目の値を変えてアクセスすることも可能です。また、このような仕様なので、二次元目の配列にアクセスするための特別な書式のようなものは、特にありません。
 
このような仕組みになっているので、一組のアドレスと配列のアドレス差分だけを格納しただけのポインタ変数によって、配列全体に適宜アクセスできます。なので、二次元目以降の要素数が多い場合でも、安心です。
 
三次元以上でも同様の処理が可能ですが、似た説明の繰り返しになるので、本ページでは説明を省略します。(おそらく本wikibooks『C言語』教科書全体でも説明が省略されると思います。)
 
== 配列の要素数を求めるイデオム ==