@http://blog.goo.ne.jp/bonsai-chat/e/1f50d0455040619c66b87b534956153a
=progCP-s%40:ポインタと多次元配列
/
progCP-s%40:ポインタと多次元配列
・教科書,参考書の復習にお使いください.
%31の第4章からの引用です.
・ぼんさいノートぼんさいノートとその補遺の参照.
Ex4-1.c
typedef int int_4[4];// for<*set*>
int m0[8]={123,4,56}, *p0=m0;
int i=1, k=2, n1=0, n2=0, n3=0;
int m1[2][4]={{100,101,102,103},
{110,111,112,113}};
int m2[4][2]={{200,201},{210,211},
{220,221},{230,231}};
int (*p1)[4]=m1, (*p2)[2]=m2; void *q;
char *p3="HELLO", c='-'; double x=3.125;
n1=p1; n2=p2; n3=n1-n2; //warning C4047:
q=&x; p0=(int*)q;
printf("%s, %x %x\n",
"■0:", p0[1], p0[0]);
printf("%s, %d, %d, %d\n",
"■1:", &m0, &m1, &m2);
printf("%s, %d, %d, %d, %d\n",
"■2:", m0, *m0+k, &m0[k], m0[k]);
printf("%s, %d, %d, %d, %d, %d\n",
"■3:", m1, (m1+i),(m1[i]), (m1[i]+k),
&m1[i][k] );
printf("%s, %d, %d, %d, %d\n",
"■4:", *m1, *(m1+i), *(m1[i]),
*(&m1[i][k]), m1[i][k]);
printf("%s, %d, %d, %d\n",
"■5:", sizeof(m1), sizeof(m1[i]),
sizeof(m1[i][k]));
printf( "%s, %d, %d, %d, %d, %d\n",
"■6:", p1, p1+i, p1[i], p1[i]+k,
&p1[i][k]);
printf( "%s, %d, %d, %d, %d\n",
"■7:", *&p1,*&p1[i], *&p1[i][k],
p1[i][k]);
printf( "%s, %d, %d, %d\n",
"■8:", sizeof(p1), sizeof(p1[i]),
sizeof(*&(p1[i][k])),
sizeof(p1[i][k]));
<*set*>
printf("■%c: %d, %d, %d\n",
c, n1, n2, n3);
■1:, 4062428, 4062316, 4062276
■2:, 4062428, 125, 4062436, 56
■3:, 4062316, 4062332, 4062332, 4062340, 4062340
■4:, 4062316, 4062332, 110, 112
■5:, 32, 16, 4
■6:, 4062316, 4062332, 4062332, 4062340, 4062340
■7:, 4062316, 4062332, 112, 112
■8:, 4, 16, 4
■-: 4062316, 4062276, 40』
★ 実行結果は「<*set*>」=「」の場合.
「*m1!=m1[0][0]」*m1[i]!=m1[i][0]」
「m1[i][k]==p1[i][k]」
「m2[i][k]==p2[i][k]」
★ &m2<&m1<&m0 とは限らない(処理系に依存).
◆ $type型のデータの配列の擬宣言を
「`$type[$n] $x;」=「$type $x[$n];」
と定め,「$x」「$x[i]」の実行文でのエイリアス
を 「$x`[]」=「$x」「$x`[i]」=「x[i]」
と定める.
◎データを格納するの領域の有無とは無関係に配列要
素のアドレスを計算できる.
★ 0≦「k」<8 でない「&m0[k]」も計算できる.
◆ 配列「m0」「m1」の擬宣言は
「`int[8] m0={123, 4, 56};」
「`int[4][2] m1={{100,101,102,103},
{110,111,112,113}};」
「*m0`[]」はint[8]型の配列
「*m1`[i]」はint[4][2]型の配列「m1`[]」の
「i」番目目の要素であるint[4]型の配列,
「m1`[i][k]」は「m1`[i]」の「k」番目の要素.
(■3:)
「&m0`[]==3603232」「&*m1`[1]==3603136」
◆ $type型のデータへのポインタの擬宣言を
「`$type[] $p;」=「$type *$p;」
と定める.「$p」がポインタであれば,つねに
「$p」=「*(&$p)」(「$p」は参照先アドレス)
「sizeof($p)==sizeof(&□)」
◆「$p」があるデータ型の配列へのポインタであると
き,実行文ではつねに次に定めるエイリアスを用い
て「$p」が配列へのポインタであることを明示する.
「$p`[]」=「$p」「$p`[0]」=「*$p」
「$p`[i]」=「$p[i]」
★「(int*) p1;」はエラー(要「typedef」)
◆ ポインタ「p0」「p1」の擬宣言は
「`int[8][] p0=m0;」
=「`int[4][2][] p1=m1;」
★ 「p1」「p1[i]」「p1[i][k]」はアドレス
「&p1」「&p1[1]」「&p1[i][k]」にあるデータと
して求める.
「p1」に「m1」を代入すると
「*&p1==*m1」
「*&p1[1]==m1[i]」
「*&p1[i][k]==m1[i][k]」(■7:)
☆「&(p1+i)」「&(p1[i]+k)」を使うとビルドでき
ない. //error C2102: '&' に左辺値がない
◎ ポインタにはデータ型が必須 (データは存在しな
くてもよい).
◎ 任意のアドレスをvoid型のポインタに設定できる
が,使うときにはキャストが必要(■0:).
◆ $type型へのキャストの実行文でのエイリアスを
「`($type)$q」=「($type)$q」と定める.
★「x」のバイナリデータを「p0[1]」「p0[0]」で
表示できる.(「p3=(char)q;」で表示しようとす
ると実行時に文字コードを復号できなくなるとエラー
になる.//(CXX0030:式は評価不能).
「&(p1+i)」「&(p1[i]+k)」はビルドできないので便宜的に次式で考える(0 ≦「n」< 8).
「*(m1+n)==m1[n/4][n%4]」
「*(p1+n)==p1[n/4][n%4]」
(1)「_<*set*>_」=「
c='A'; n1=p1[i][k]; n2 = p2[i][k]; n3 =
p2[i][k+3];」
『■A: 112, 220, 231』
「n3==*(p2+i*2+k+3)」
「n3==(p2[i+(k+3)/2][(k+3)%2]」
(2)「_<*set*>」=「c='B'; n1 = p1[i][k];
p1++; n2 = p1[i-1][k]; n3 = p1[0][0];」
『■B: 112, 112, 110』
「p1++;」で「p1==m+1」に変わるから(■6:)
「*(p1+i*4+k)==*(m1+(1+i)*4+k)」
(3)「<*set*>」=「c='C'; n1 = m1[i][k];
q = &m1[1][1]; p1 = (int_4*)q;
n2 = p1[i-1][k-1]; n3 = p1[0][0];」
『■C: 112, 112, 111』
「p1[i][k]」は「&m1[1][1]」に先頭アドレスがある多次元配列の要素とみなされるから
「*(p1+i*4+k)==*(m1+(1+i)*4+k+1)」
このことは「c='D'; n3 = p1[-1][-1];」に変更した結果でも確認できる.
『■D: 112, 112, 100』
Ex4-2.c
char s[7][8]=={"Sun","Mon","Tue",
"Wed","Thu","Fri","Sat",};
char *p[7]={"Sun","Mon","Tue",
"Wed","Thu","Fri","Sat",};
<*set*>
printf("%d,%d\n", sizeof(s), sizeof(p));
『 56,28』
★「<*set*>」=「」の例は省略.
コピーやソートは「s」より「p」の方が簡単.
☆「s」はchar型データの多次元配列,「p」はポインタの配列でこれらの擬宣言は
「`char[8][7] s={"Sun","Mon","Tue",
"Wed","Thu","Fri","Sat",};」
「`char[][7] p={"Sun","Mon","Tue",
"Wed","Thu","Fri","Sat",};」
多次元配列の擬宣言は初心者に分かり難いが,Cでの宣言の考え方は複雑な宣言《pp.148-151》に示されている例「char (*(*x[3])())[5];」を
「char (*(*x[3])())[5];」
「char[5] *(*x[3])(); 」
「char[5]* (*x[3])(); 」
「()(char[5]*) *x[3]; 」
「(()(char[5]*))* x[3]; 」
「(()(char[5]*))*[3] x; 」
と変形すると, x が「 array [3] of pointer to function returning pointer to array [5] of char 」であることがよく分かる.
《wikipedia(C言語)》//目次の「 1 特徴」
http://ja.wikipedia.org/wiki/C%E8%A8%80%E8%AA%9E
/*-------------------------------------------------