配列とポインタの煩わしいと言うか、今一分からない関係を整理しようと調べたところ、「C言語には多次元配列は存在しない、二次元配列と呼ばれるものは配列の配列を利用して実現しているに過ぎない」の様な内容を目にし、色々と試してみました。
気付いた事は、
C言語の配列は、事実上、一次元配列を使って実現されている様です。
& 演算子は、その変数を指すアドレスを作り、ポインタに割り当てます(int *ptr の時、ptr がポインタ)。
array[n] と *(array + n) は等価と定義されており、n[array] とも等価です。
また、array と &array[0] は等価、つまり array == &array[0] です。
char *s[n] はポインタの配列(要素は char のポインタ変数)
char (*s)[n] は配列のポインタ(要素は char の変数)
int array[n] の時、int *p = array は *p の一次元の形で表されます。
int array[n] の時、int **p = &array は (*p)[n] の二次元の形で表されます。
char *s[n] の時、char **p = s は **p の二次元の形で表されます。
char *s[n] の時、char ***p = &s は *(*p)[n] の三次元の形で表されます。
&array は配列のポインタを表し、ポインタのポインタ(ダブルポインタ)ではありません。
&s は(文字列の)ポインタの配列のポインタを表し、ポインタのポインタのポインタ(トリプルポインタ)ではありません。
ですが、そうとばかりは限らない場合も・・・
関数の間接参照レベルで 'char **' と 'char *[n]' は同じ(ポインタの配列)。これは良しとして、
厳しくウォーニングを出力させると、
関数の間接参照レベルで 'char ***' と 'char *(*)[5]' では異なっつて(配列のポインタのポインタ)いたり、
間接参照レベルで 'int **' と 'int (*)[5]' では異なって(配列のポインタ)いたり、
など、結構出てきました。
ウォーニングを出さないようにするには、関数の仮引数を char *(*str2)[5] にしたり、目を瞑ったり(これで上手く行く)。
兎に角、C言語は配列の添字つまりサイズに、殊の外五月蠅いと言うか厳格です。(見かけ上の)三次元配列も、配列の配列の配列で表現する(せざるを得ない?)ので、当然と言えば当然なのかもしれません。
ですので、配列は使えど関数の呼び出しは、ポインタで渡すのが無難です。
などでしょうか。
sub3、sub8、sub9の関数定義と呼出し元を見比べれば分かる通り、配列を使わず、定見無くポインタを使えば万事(?)驚く程に上手く行きます。配列の添字やセグメンテーションフォルトで悩む必要もありません。
void sub3(int **p, int *ap) {
sub3(dim, &dim);
void sub8(char **str1, char *(*str2)[5]) {
sub8(s2, &s2);
void sub9(char **str1, char **str2) {
sub9(s2, &s2);
お試し環境
WindowsXP 32bit Edition
Visual C++ 2008
/*------------------------------ お試し結果 -------------------------------*/
D:\vc2008\cplchk>test
sub1 : p[0][0]=123 p[0][1]=345 p[1][0]=567 p[1][1]=789 p[2][0]=abc p[2][1]=def
sub1 : p = 0012FF58, p[0] = 0012FF58, p[1] = 0012FF60, p[2] = 0012FF68
sub2 : p = 0012FF58, *p = 123, *(p + 1) = 345
sub3 : p = 0012FF58, *p = 123, *(p + 2) = 567
sub3 : ap = 0012FF58, *ap = 123, *(ap + 3) = 789
sub4 : p = 0012FF58, *p = 0012FF58, p[0] = 0012FF58, (*p)[0]) = 123, (*p)[1]) = 345, (*p)[2]) = 567
sub5 : p = 0012FF58, *p = 123, p[3] = 789, p[4] = abc, *(p + 5) = def
sub1 - sub5 test end
sub6 : p1 = 0012FEEC, p2 = 0012FEEC, p3 = 0012FEEC, p5 = 0012FEEC
sub6 : *p4 = 0012FEEC, *p4 + 1 = 0012FEF0, *p4 + 2 = 0012FEF4, *p4 + 3 = 0012FEF8, *p4 + 4 = 0012FEFC
sub6 : *p5 = 0012FEEC, *p5 + 1 = 0012FEF0, *p5 + 2 = 0012FEF4, *p5 + 3 = 0012FEF8, *p5 + 4 = 0012FEFC
sub6 : &(*p4[0]) = 0012FEEC, &(*p4[1]) = 00403160, &(*p4[2]) = 39520179, &(*p4[3]) = FFFFFFFE, &(*p4[4]) = 00401D95
sub6 : *p5[0] = 00001111, *p5[1] = 0012FEEC, *p5[2] = 0012FEEC, *p5[3] = 0012FF78, *p5[4] = 0040DAFC
sub6 : *p1 = 1111, *(p1 + 1) = 2222, *(p1 + 2) = 3333, *(p1 + 3) = 4444
sub6 : *p2 = 1111, *(p2 + 1) = 2222, *(p2 + 2) = 3333, *(p2 + 3) = 4444
sub6 : *p3 = 1111, *(p3 + 1) = 2222, *(p3 + 2) = 3333, *(p3 + 3) = 4444
sub6 : *(*p4) = 1111, *(*p4 + 1) = 2222, *(*p4 + 2) = 3333, *(*p4 + 3) = 4444
sub6 : *(*p5) = 1111, *(*p5 + 1) = 2222, *(*p5 + 2) = 3333, *(*p5 + 3) = 4444
sub6 : (*p4)[0] = 1111, (*p4)[1] = 2222, (*p4)[2] = 3333, (*p4)[3] = 4444, (*p4)[4] = 5555
sub6 : (*p5)[0] = 1111, (*p5)[1] = 2222, (*p5)[2] = 3333, (*p5)[3] = 4444, (*p5)[4] = 5555
sub6 : i= 0, p2 + i = 0012FEEC, *(p2 + i) = 1111
sub6 : i= 1, p2 + i = 0012FEF0, *(p2 + i) = 2222
sub6 : i= 2, p2 + i = 0012FEF4, *(p2 + i) = 3333
sub6 : i= 3, p2 + i = 0012FEF8, *(p2 + i) = 4444
sub6 : i= 4, p2 + i = 0012FEFC, *(p2 + i) = 5555
sub6 : i= 5, p2 + i = 0012FF00, *(p2 + i) = 12feec
sub6 : i= 6, p2 + i = 0012FF04, *(p2 + i) = 12feec
sub6 test end
sub7 : i = 0, p[i] = 123, *(p + i) = 123
sub7 : i = 1, p[i] = abcdefg, *(p + i) = abcdefg
sub7 : i = 2, p[i] = 456789, *(p + i) = 456789
sub7 : i = 3, p[i] = HIJK, *(p + i) = HIJK
sub7 : **p : 123
sub7 : **p : abcdefg
sub7 : **p : 456789
sub7 : **p : HIJK
sub7 : *p[] : 123
sub7 : *p[] : abcdefg
sub7 : *p[] : 456789
sub7 : *p[] : HIJK
sub7 test end
sub8 : p1 = 0012FF40, *p1 = 0040DB0C, &p1 = 0012FF14, &*p1 = 0012FF40
sub8 : p2 = 0012FF40, *p2 = 0012FF40, *(*p2) = 0040DB0C, &p2 = 0012FF18, &*p2 = 0012FF40, &*(*p2) = 0012FF40
sub8 : **p1 = z, *p1 = zero
sub8 : **(*p2) = z, *(*p2) = zero
sub8 : p2[0] = 0012FF40, p2[1] = 0012FF54, p2[2] = 0012FF68, p2[3] = 0012FF7C, p2[4] = 0012FF90
sub8 : *p2[0] = 0040DB0C, *p2[1] = 0040DB48, *p2[2] = 00000ABC, *p2[3] = 00401F6F, *p2[4] = 00000012
sub8 : *(*p2)[0] = z, (*p2)[0] = zero
sub8 : i= 0, p1 + i = 0012FF40, *(p1 + i) = 0040DB0C, *(p1 + i) = zero
sub8 : i= 1, p1 + i = 0012FF44, *(p1 + i) = 0040DB18, *(p1 + i) = one
sub8 : i= 2, p1 + i = 0012FF48, *(p1 + i) = 0040DB20, *(p1 + i) = two
sub8 : i= 3, p1 + i = 0012FF4C, *(p1 + i) = 0040DB2C, *(p1 + i) = three
sub8 : i= 4, p1 + i = 0012FF50, *(p1 + i) = 0040DB3C, *(p1 + i) = four
sub8 : i= 5, p1 + i = 0012FF54, *(p1 + i) = 40db48
sub8 : i= 6, p1 + i = 0012FF58, *(p1 + i) = 123
sub8 : **p1 : zero
sub8 : **p1 : one
sub8 : **p1 : two
sub8 : **p1 : three
sub8 : **p1 : four
sub8 : i= 0, *p2 + i = 0012FF40, *(*p2 + i) = 0040DB0C, *(*p2 + i) = zero
sub8 : i= 1, *p2 + i = 0012FF44, *(*p2 + i) = 0040DB18, *(*p2 + i) = one
sub8 : i= 2, *p2 + i = 0012FF48, *(*p2 + i) = 0040DB20, *(*p2 + i) = two
sub8 : i= 3, *p2 + i = 0012FF4C, *(*p2 + i) = 0040DB2C, *(*p2 + i) = three
sub8 : i= 4, *p2 + i = 0012FF50, *(*p2 + i) = 0040DB3C, *(*p2 + i) = four
sub8 : i= 5, *p2 + i = 0012FF54, *(*p2 + i) = 40db48
sub8 : i= 6, *p2 + i = 0012FF58, *(*p2 + i) = 123
sub8 : ***p2 : zero
sub8 : ***p2 : one
sub8 : ***p2 : two
sub8 : ***p2 : three
sub8 : ***p2 : four
sub8 : **p2[] : zero
sub8 : **p2[] : one
sub8 : **p2[] : two
sub8 : **p2[] : three
sub8 : **p2[] : four
sub8 test end
sub9 : &p1 = 0012FF14, p1 = 0012FF40, *p1 = 0040DB0C, **p1 = z
sub9 : &p2 = 0012FF18, p2 = 0012FF40, *p2 = 0040DB0C, **p2 = z
sub9 : i= 0, p1 + i = 0012FF40, *(p1 + i) = 0040DB0C, *(p1 + i) = zero
sub9 : i= 1, p1 + i = 0012FF44, *(p1 + i) = 0040DB18, *(p1 + i) = one
sub9 : i= 2, p1 + i = 0012FF48, *(p1 + i) = 0040DB20, *(p1 + i) = two
sub9 : i= 3, p1 + i = 0012FF4C, *(p1 + i) = 0040DB2C, *(p1 + i) = three
sub9 : i= 4, p1 + i = 0012FF50, *(p1 + i) = 0040DB3C, *(p1 + i) = four
sub9 : i= 5, p1 + i = 0012FF54, *(p1 + i) = 40db48
sub9 : i= 6, p1 + i = 0012FF58, *(p1 + i) = 123
sub9 : i= 0, p2 + i = 0012FF40, *(p2 + i) = 0040DB0C, *(p2 + i) = zero
sub9 : i= 1, p2 + i = 0012FF44, *(p2 + i) = 0040DB18, *(p2 + i) = one
sub9 : i= 2, p2 + i = 0012FF48, *(p2 + i) = 0040DB20, *(p2 + i) = two
sub9 : i= 3, p2 + i = 0012FF4C, *(p2 + i) = 0040DB2C, *(p2 + i) = three
sub9 : i= 4, p2 + i = 0012FF50, *(p2 + i) = 0040DB3C, *(p2 + i) = four
sub9 : i= 5, p2 + i = 0012FF54, *(p2 + i) = 40db48
sub9 : i= 6, p2 + i = 0012FF58, *(p2 + i) = 123
sub9 test end
cst1 : str1 = 0040DB44 - ABC, str2 = 0040DB48 - DEF
cst1 : src = 0040DB44, *src = A
cst2 : str1 = 0040DB44 - ABC, str2 = 0040DB48 - DEF
cst2 : src = 0040DB44, *src = A
cst3 : str1 = 0040DB44 - ABC, str2 = 0040DB48 - DEF
cst3 : src = 0040DB48, *src = a
cst4 : str1 = 0040DB44 - ABC, str2 = 0040DB48 - aEF
cst4 : src = 0040DB48, *src = a
cst5 : str1 = 0040DB44 - ABC, str2 = 0040DB48 - aEF
cst5 : src = 0040DB48, *src = a
const string test end
D:\vc2008\cplchk>
/*---------------------------------------------------------------------------*/
/*------------------------------ お試しソース -----------------------------*/
#include "stdio.h"
#include "string.h"
void sub1(int p[][2]) {
printf("sub1 : p[0][0]=%x p[0][1]=%x p[1][0]=%x p[1][1]=%x p[2][0]=%x p[2][1]=%x\n", p[0][0], p[0][1], p[1][0], p[1][1], p[2][0], p[2][1]);
printf("sub1 : p = %p, p[0] = %p, p[1] = %p, p[2] = %p\n", p, p[0], p[1], p[2]);
}
void sub2(int *p) {
printf("sub2 : p = %p, *p = %x, *(p + 1) = %x\n", p, *p, *(p + 1));
}
void sub3(int **p, int *ap) {
printf("sub3 : p = %p, *p = %x, *(p + 2) = %x\n", p, *p, *(p + 2));
printf("sub3 : ap = %p, *ap = %x, *(ap + 3) = %x\n", ap, *ap, *(ap + 3));
}
void sub4(int (*p)[2]) {
printf("sub4 : p = %p, *p = %p, p[0] = %p, (*p)[0]) = %x, (*p)[1]) = %x, (*p)[2]) = %x\n", p, *p, p[0], (*p)[0], (*p)[1], (*p)[2]);
}
void sub5(int *p[]) {
printf("sub5 : p = %p, *p = %x, p[3] = %x, p[4] = %x, *(p + 5) = %x\n", p, *p, p[3], p[4], *(p + 5));
}
void sub6(void) {
int array[5] = {0x1111, 0x2222, 0x3333, 0x4444, 0x5555};
int i, *p1, *p2, **p3, *p4[5], (*p5)[5];
p1 = array;
p2 = &array;
p3 = &array;
*p4 = &array;
p5 = &array;
printf("sub6 : p1 = %p, p2 = %p, p3 = %p, p5 = %p\n", p1, p2, p3, p5);
printf("sub6 : *p4 = %p, *p4 + 1 = %p, *p4 + 2 = %p, *p4 + 3 = %p, *p4 + 4 = %p\n", *p4, *p4 + 1, *p4 + 2, *p4 + 3, *p4 + 4);
printf("sub6 : *p5 = %p, *p5 + 1 = %p, *p5 + 2 = %p, *p5 + 3 = %p, *p5 + 4 = %p\n", *p5, *p5 + 1, *p5 + 2, *p5 + 3, *p5 + 4);
printf("sub6 : &(*p4[0]) = %p, &(*p4[1]) = %p, &(*p4[2]) = %p, &(*p4[3]) = %p, &(*p4[4]) = %p\n", &(*p4[0]), &(*p4[1]), &(*p4[2]), &(*p4[3]), &(*p4[4]));
printf("sub6 : *p5[0] = %p, *p5[1] = %p, *p5[2] = %p, *p5[3] = %p, *p5[4] = %p\n", *p5[0], *p5[1], *p5[2], *p5[3], *p5[4]);
printf("sub6 : *p1 = %x, *(p1 + 1) = %x, *(p1 + 2) = %x, *(p1 + 3) = %x\n", *p1, *(p1 + 1), *(p1 + 2), *(p1 + 3));
printf("sub6 : *p2 = %x, *(p2 + 1) = %x, *(p2 + 2) = %x, *(p2 + 3) = %x\n", *p2, *(p2 + 1), *(p2 + 2), *(p2 + 3));
printf("sub6 : *p3 = %x, *(p3 + 1) = %x, *(p3 + 2) = %x, *(p3 + 3) = %x\n", *p3, *(p3 + 1), *(p3 + 2), *(p3 + 3));
printf("sub6 : *(*p4) = %x, *(*p4 + 1) = %x, *(*p4 + 2) = %x, *(*p4 + 3) = %x\n", *(*p4), *(*p4 + 1), *(*p4 + 2), *(*p4 + 3));
printf("sub6 : *(*p5) = %x, *(*p5 + 1) = %x, *(*p5 + 2) = %x, *(*p5 + 3) = %x\n", *(*p5), *(*p5 + 1), *(*p5 + 2), *(*p5 + 3));
printf("sub6 : (*p4)[0] = %x, (*p4)[1] = %x, (*p4)[2] = %x, (*p4)[3] = %x, (*p4)[4] = %x\n", (*p4)[0], (*p4)[1], (*p4)[2], (*p4)[3], (*p4)[4]);
printf("sub6 : (*p5)[0] = %x, (*p5)[1] = %x, (*p5)[2] = %x, (*p5)[3] = %x, (*p5)[4] = %x\n", (*p5)[0], (*p5)[1], (*p5)[2], (*p5)[3], (*p5)[4]);
for(i = 0; i < 7; i++) {
printf("sub6 : i= %d, p2 + i = %p, *(p2 + i) = %x\n", i, p2 + i, *(p2 + i));
}
}
void sub7(int no, char **p) {
int i, j, k;
for(i = 0; i < no; i++) {
printf("sub7 : i = %d, p[i] = %s, *(p + i) = %s\n", i, p[i], *(p + i));
}
for(i = 0; i < no; i++) {
k = strlen(*(p + i));
printf("sub7 : **p : ");
for(j = 0; j < k; j++) {
printf("%c", *(*(p + i) + j));
}
printf("\n");
}
for(i = 0; i < no; i++) {
k = strlen(p[i]);
printf("sub7 : *p[] : ");
for(j = 0; j < k; j++) {
printf("%c", *(p[i] + j));
}
printf("\n");
}
}
void sub8(char **str1, char *(*str2)[5]) {
char **p1 = str1, *(*p2)[5] = str2;
int i, j, k;
printf("sub8 : p1 = %p, *p1 = %p, &p1 = %p, &*p1 = %p\n", p1, *p1, &p1, &*p1);
printf("sub8 : p2 = %p, *p2 = %p, *(*p2) = %p, &p2 = %p, &*p2 = %p, &*(*p2) = %p\n", p2, *p2, *(*p2), &p2, &*p2, &*(*p2));
printf("sub8 : **p1 = %c, *p1 = %s\n", **p1, *p1);
printf("sub8 : **(*p2) = %c, *(*p2) = %s\n", **(*p2), *(*p2));
printf("sub8 : p2[0] = %p, p2[1] = %p, p2[2] = %p, p2[3] = %p, p2[4] = %p\n", p2[0], p2[1], p2[2], p2[3], p2[4]);
printf("sub8 : *p2[0] = %p, *p2[1] = %p, *p2[2] = %p, *p2[3] = %p, *p2[4] = %p\n", *p2[0], *p2[1], *p2[2], *p2[3], *p2[4]);
printf("sub8 : *(*p2)[0] = %c, (*p2)[0] = %s\n", *(*p2)[0], (*p2)[0]);
for(i = 0; i < 7; i++) {
if(i < 5) {
printf("sub8 : i= %d, p1 + i = %p, *(p1 + i) = %p, *(p1 + i) = %s\n", i, p1 + i, *(p1 + i), *(p1 + i));
} else {
printf("sub8 : i= %d, p1 + i = %p, *(p1 + i) = %x\n", i, p1 + i, *(p1 + i));
}
}
for(i = 0; i < 5; i++) {
k = strlen(*(p1 + i));
printf("sub8 : **p1 : ");
for(j = 0; j < k; j++) {
printf("%c", *(*(p1 + i) + j));
}
printf("\n");
}
for(i = 0; i < 7; i++) {
if(i < 5) {
printf("sub8 : i= %d, *p2 + i = %p, *(*p2 + i) = %p, *(*p2 + i) = %s\n", i, *p2 + i, *(*p2 + i), *(*p2 + i));
} else {
printf("sub8 : i= %d, *p2 + i = %p, *(*p2 + i) = %x\n", i, *p2 + i, *(*p2 + i));
}
}
for(i = 0; i < 5; i++) {
k = strlen(*(*p2 + i));
printf("sub8 : ***p2 : ");
for(j = 0; j < k; j++) {
printf("%c", *(*(*p2 + i) + j));
}
printf("\n");
}
for(i = 0; i < 5; i++) {
k = strlen((*p2)[i]);
printf("sub8 : **p2[] : ");
for(j = 0; j < k; j++) {
printf("%c", *((*p2)[i] + j));
}
printf("\n");
}
}
void sub9(char **str1, char **str2) {
char **p1 = str1, **p2 = str2;
int i;
printf("sub9 : &p1 = %p, p1 = %p, *p1 = %p, **p1 = %c\n", &p1, p1, *p1, **p1);
printf("sub9 : &p2 = %p, p2 = %p, *p2 = %p, **p2 = %c\n", &p2, p2, *p2, **p2);
for(i = 0; i < 7; i++) {
if(i < 5) {
printf("sub9 : i= %d, p1 + i = %p, *(p1 + i) = %p, *(p1 + i) = %s\n", i, p1 + i, *(p1 + i), *(p1 + i));
} else {
printf("sub9 : i= %d, p1 + i = %p, *(p1 + i) = %x\n", i, p1 + i, *(p1 + i));
}
}
for(i = 0; i < 7; i++) {
if(i < 5) {
printf("sub9 : i= %d, p2 + i = %p, *(p2 + i) = %p, *(p2 + i) = %s\n", i, p2 + i, *(p2 + i), *(p2 + i));
} else {
printf("sub9 : i= %d, p2 + i = %p, *(p2 + i) = %x\n", i, p2 + i, *(p2 + i));
}
}
}
void cst1(char *dest, const char *src) {
printf("cst1 : str1 = %p - %s, str2 = %p - %s\n", dest, dest, src, src);
src = dest; /* possible */
// *src = 'a'; /* error */
printf("cst1 : src = %p, *src = %c\n", src, *src);
}
void cst2(char *dest, char const *src) {
printf("cst2 : str1 = %p - %s, str2 = %p - %s\n", dest, dest, src, src);
src = dest; /* possible */
// *src = 'a'; /* error */
printf("cst2 : src = %p, *src = %c\n", src, *src);
}
void cst3(char *dest, char * const src) {
printf("cst3 : str1 = %p - %s, str2 = %p - %s\n", dest, dest, src, src);
// src = dest; /* error */
*src = 'a'; /* possible */
printf("cst3 : src = %p, *src = %c\n", src, *src);
}
void cst4(char *dest, const char * const src) {
printf("cst4 : str1 = %p - %s, str2 = %p - %s\n", dest, dest, src, src);
// src = dest; /* error */
// *src = 'a'; /* error */
printf("cst4 : src = %p, *src = %c\n", src, *src);
}
void cst5(char *dest, char const * const src) {
printf("cst5 : str1 = %p - %s, str2 = %p - %s\n", dest, dest, src, src);
// src = dest; /* error */
// *src = 'a'; /* error */
printf("cst5 : src = %p, *src = %c\n", src, *src);
}
void main(void)
{
int dim[3][2] = {0x123, 0x345, 0x567, 0x789, 0xabc, 0xdef};
char **p, *s1[4] = {"123", "abcdefg", "456789", "HIJK"};
char *s2[5] = {"zero", "one", "two", "three", "four"};
char *st1 = "ABC", *st2 = "DEF";
sub1(dim);
sub2(dim);
sub3(dim, &dim);
sub4(dim);
sub5(dim);
printf("sub1 - sub5 test end\n\n");
sub6();
printf("sub6 test end\n\n");
p = s1;
sub7((int)4, p);
printf("sub7 test end\n\n");
sub8(s2, &s2);
printf("sub8 test end\n\n");
sub9(s2, &s2);
printf("sub9 test end\n\n");
cst1(st1, st2);
cst2(st1, st2);
cst3(st1, st2);
cst4(st1, st2);
cst5(st1, st2);
printf("const string test end\n\n");
}
/*---------------------------------------------------------------------------*/
/*------------------------ 配列とポインタの不思議 -----------------------*/
#include <stdio.h>
void main(void) {
int i, a[4];
a[0] = 10;
*(1 + a) = 20;
*(a + 2) = 30;
3[a] = 40;
for(i = 0; i < 4; i++) {
printf("a[i] = %d\n", a[i]);
}
}
上記の出力結果は? お試しあれ。
/*---------------------------------------------------------------------------*/