少し長くなってしまいました。m(_ _)m
これが学校の課題だとすると、生徒たちに C言語のアドレスのしくみを、本当に理解させたいんだな、という感じがしました。
なるべく理解できるように回答したつもりですが、分かりにくかったらスミマセン。
1 を足して値が 4 進んだり、8 進んだりするものは、C 言語の中ではポインタしかありません。
(ポインタとは、少し乱暴に説明すると、「住所を書いた1枚の紙きれ」みたいなものです。その住所を見ると目的の値が置いてあったりします)
問題は変数 a については規定していなくて、
b, c については「~配列である」と規定しています。
● a
a について、1 を足して 4 進むと言ったらそれは int 型のポインタです。
なので、a は int *a; と宣言すれば良いでしょう。
(または、float *a; 、long int *a; 、char a[3][4]; としても、1 を足して 4 進みます)
a をポインタとして表示する( printf() で %p を使う)とそのアドレスが 16 進数で表示されます。
a + 1 としたとき、int 型のサイズ分アドレスが進みます。
int 型のサイズは 4 なので、アドレスは 4 進みます。
● b
b については、問題文で「b はint 型の2 次元配列とする」と規定されています。
そして、printf() では b, b+1, b+2 と順次書いていて、これらの間隔が 12 だと言っています。
前提知識として、C 言語では「配列はポインタと似た動きをする」というのがあります。
たとえば、
int d[ 4 ]; のように配列を宣言して
printf( "%p", d ); とすると、d は配列ですがポインタのようにそのアドレスを表示します。
printf( "%p", d + 1 ); とすると、d は int 型の配列なので、int 型のサイズ分、つまり 4 進めたアドレスが表示されます。
アドレスが +12 される、というのは、サイズ 4 の 3 つ分で 12 と考えることができます。つまり、int 型が 3 つあれば 12 です。
int b[ 3 ];
と宣言したとき、b に 1 を足すと、int 型のサイズ分進むということでした。
では、2 次元配列にして、
int b[ 3 ][ 2 ];
と宣言したとき、b に 1 を足すと、どれだけのサイズ進むでしょうか。
b[ 0 ] には、b[ 0 ][ 0 ] と、b[ 0 ][ 1 ] の 2 つ分の要素が入っています。
そして、
b[ 1 ] には、b[ 1 ][ 0 ] と、b[ 1 ][ 1 ] の 2 つ分の要素が入っています。
b に 1 を足すというのは、この 2 つ分の要素進めるということになります。
int 型 2 つ分なので、4 x 2 = 8 で、8 進みます。
問題は +12 (12 進む)と言っているので、
int b[ 3 ][ 3 ];
ということになります。
b[ 0 ] には、b[ 0 ][ 0 ] と、b[ 0 ][ 1 ] と、b[ 0 ][ 2 ] の 3 つ分の要素が入っています。
b[ 1 ] には、b[ 1 ][ 0 ] と、b[ 1 ][ 1 ] と、b[ 1 ][ 2 ] の 3 つ分の要素が入っています。
int 型 3 つ分なので、4 x 3 = 12 で、これで 12 進みます。
● c
c については、問題文で「c は1 次元配列とする」と規定されています。型の指定はありません。
そして、printf() では c, c+1, c+2 と順次書いていて、これらの間隔が 8 だと言っています。
C 言語でサイズが 8 である型は、double 型です。(他に「long long」型も 8 です)
その 1 次元配列であれば、+1 するたびに 8 ずつアドレスが進むことが期待できます。
double c[ 3 ];
と宣言すればよいでしょう。
●%?
printf() でこれらのアドレスを表示するには、ポインタと同様に %p を使います。
■プログラム1
以上をプログラムにすると以下のようになります。
#include <stdio.h>
int main(void)
{
int *a;//
int b[ 3 ][ 3 ];//
double c[ 3 ];//
printf("%p\n",a);
printf("%p\n",a+1);
printf("%p\n",a+2);
printf("%p\n",b);
printf("%p\n",b+1);
printf("%p\n",b+2);
printf("%p\n",c);
printf("%p\n",c+1);
printf("%p\n",c+2);
return 0;
}
実行ファイルには「32 bit アプリ」と「64 bit アプリ」の違いがあります。
32 bit アプリを作るコンパイラで作ると、%p で表示される 16 進数の桁数が 8 桁になります。
64 bit アプリを作るコンパイラで作ると、%p で表示される 16 進数の桁数が 12 桁、または 16 桁になります。
~bit アプリの bit 数が大きいと、それだけ広大なメモリにアクセスできるので、アドレスを表現する桁数も増えるんです。
どんなコンパイラを使っているかで結果の表示桁数が異なるので注意してください。
■プログラム2
以下のプログラムは、横に上行との値の差を表示して確認ができます。おまけです。(画像)
#include <stdio.h>
// 2つのアドレスの差を求める関数
int test( void *p1, void *p2 ) {
int a1 = (long int)p1;
int a2 = (long int)p2;
return (int)(a1 - a2);
}
int main(void)
{
int *a;//
int b[ 3 ][ 3 ];//
double c[ 3 ];//
printf("%p\n",a);
printf("%p, %d\n",a+1, test(a+1,a) );
printf("%p, %d\n",a+2, test(a+2,a+1) );
printf("%p\n",b);
printf("%p, %d\n",b+1, test(b+1,b) );
printf("%p, %d\n",b+2, test(b+2,b+1) );
printf("%p\n",c);
printf("%p, %d\n",c+1, test(c+1,c) );
printf("%p, %d\n",c+2, test(c+2,c+1) );
return 0;
}