• ベストアンサー

配列とポインタについて

以下のような matrixの二次元配列の引数があるのですが、これを keisan2に渡す時にどのように記述すれば良いのでしょうか? ???部分が知りたいです。 また、char **matrixと matrix[][3]は違うものですか? 覚えるコツも知りたいです。 int keisan(int data, char matrix[][3]) { // 省略 return keisan2(dat, ???); } int keisan2(int data, char matrix[][3]) { // 省略 return 0; }

質問者が選んだベストアンサー

  • ベストアンサー
回答No.7

参考HPでも載せときますね http://www.geocities.co.jp/SiliconValley-Bay/7437/c/c4.htm http://sometime.minidns.net/~ccgi/pointer_array.html ポインタ配列とポインタのポインタを同じだと言い張る人がいて驚いた。

その他の回答 (9)

  • Tacosan
  • ベストアンサー率23% (3656/15482)
回答No.10

char matrix[][3] における matrix の型は char[][3]>#9. ポインタに変換されたあとでは char (*)[3].

回答No.9

突っ込みたくて、アカウントまでとってしまいました^^;; >また、char **matrixと matrix[][3]は違うものですか? >覚えるコツも知りたいです。 何人かのかたも回答していますが別のものです。 「型」を意識すると理解できると思います。 char **matrix はあくまで 「char **」という型ですが matrix[][3] はたぶん、「char」という型です。 (char は僕の補完です。) 両者を同じに考えていると将来、メモリ周りで悩むことになるかもしれません。 #include <stdio.h> int main(int argc, char *argv[]) { char a[][4] = {"ABC", "DEF", "GHI" }; char *b[4] = {"abc", "def", "ghi" }; a[0][0] = 'R'; b[0][0] = 'r'; // ← NG printf("%s\n", a[0]); printf("%s\n", b[0]); return 0; }

  • Tacosan
  • ベストアンサー率23% (3656/15482)
回答No.8

#6 の 1行目を詳しく書くと, #5 の matrixsub において各引数はそれぞれ char **matrix1, char matrix2[][3], char *matrix3[3] と宣言されています. このうち matrix1 の型は直ちに char ** であることがわかります. 問題は matrix2, matrix3 ですが, これはそれぞれ「char [3] の配列」及び「char * の大きさ 3 の配列」と宣言されています. しかし, C/C++ の規格では「引数を配列と宣言した場合, 自動的にポインタであると解釈する」という規定があります. なので, コンパイラが理解する本当の型はそれぞれ「char [3] へのポインタ」, 「char * へのポインタ」です. 従って, 実際にはそれぞれ char (*matrix2)[3], char **matrix3 であるとみなされます (matrix2 でかっこが付いているのは優先順位の関係による). つまり, matrix1 と matrix はどちらも同じ型 char ** であり, 同じ扱いを受けるのが自然です.

  • Tacosan
  • ベストアンサー率23% (3656/15482)
回答No.6

matrixsub において matrix1 と matrix3 は同じ型を持つので, その要素にアクセスするコードも全く同じになるのが自然なんですけど>#5. #3 はそんなことは言ってなくて, 例えば void foo() { int matrix1[4][3]; int *matrix2[4]; int **matrix3; int x, y; /* matrix2, matrix3 は適切にメモリが割り当てられているとする */ printf("%d %d %d\n", matrix1[x][y], matrix2[x][y], matrix3[x][y]); /* 以下略 */ } の printf のところでアクセスするコードが違うよね, って話でしょう. この場合 matrix1, matrix2, matrix3 はすべて異なる型であり, 実際に違うコードが出るはずです. 「違う」ことがあまりにも明らかなので確かめる気はありません.

  • zwi
  • ベストアンサー率56% (730/1282)
回答No.5

横から失礼します。 私も、 char **matrix; char *matrix[3]; は同じだと思うんですよ、なので代わりに検証コードを書いてみました。 cygwinのgccを使っています。 void matrixsub( char **matrix1, char matrix2[][3], char *matrix3[3]); int main(void) { char matrixA[3][3]; char *matrixB[3]; char matrixB0[3]; char matrixB1[3]; char matrixB2[3]; int i,j; matrixB[0] = matrixB0; matrixB[1] = matrixB1; matrixB[2] = matrixB2; for( i=0; i<3 ; i++ ) { for( j=0; j<3 ; j++ ) { matrixA[i][j] = i*10+j; matrixB[i][j] = 100+i*10+j; } } matrixsub( matrixB, matrixA, matrixB ); } void matrixsub( char **matrix1, char matrix2[][3], char *matrix3[3]) { int i,j; for( i=0; i<3 ; i++ ) { for( j=0; j<3 ; j++ ) { printf( "1:%02d 2:%02d 3:%02d ", matrix1[i][j], matrix2[i][j], matrix3[i][j] ); printf( "\n" ); } } } で、オプティマイズ無しコンパイル時のアセンブルコードのprintfの一部分を載せます。 movl -4(%ebp), %eax # i, i leal 0(,%eax,4), %ecx #, tmp60 movl 16(%ebp), %edx # matrix3, matrix3 movl -8(%ebp), %eax # j, j addl (%ecx,%edx), %eax #* matrix3, tmp62 movsbl (%eax),%eax #, tmp64 movl %eax, 12(%esp) # tmp64, movl -4(%ebp), %edx # i, i movl %edx, %eax # i, i addl %eax, %eax # i addl %edx, %eax # i, i addl -8(%ebp), %eax # j, tmp67 addl 12(%ebp), %eax # matrix2, tmp68 movsbl (%eax),%eax #, tmp69 movl %eax, 8(%esp) # tmp69, movl -4(%ebp), %eax # i, i leal 0(,%eax,4), %ecx #, tmp72 movl 8(%ebp), %edx # matrix1, matrix1 movl -8(%ebp), %eax # j, j addl (%ecx,%edx), %eax #* matrix1, tmp74 movsbl (%eax),%eax #, tmp76 movl %eax, 4(%esp) # tmp76, アセンブルコードを見ると分ると思いますが、matrix1と3は同じに扱われます。matrix2はやはり違う扱いを受けています。 思った通りと言うか、なるほどやっぱりな結果でした。

kourei
質問者

補足

非常に混乱しそうですが、アセンブルの結果で同じだったからといって 同じものだといえるのでしょうか? ポインタのポインタは、単なるポインタをセットするのみで ポインタ配列にならないと思いますが・・・?

  • asuncion
  • ベストアンサー率33% (2126/6288)
回答No.4

>#3さん >どれも「値を取り出す時に、同じ書き方が可能」ですが「実際に値を取り出す方法」は違っています。 どうもここのところがしっくりこないので、 サンプルコードか何かで動きを体感できるように していただけませんでしょうか?

  • chie65535
  • ベストアンサー率43% (8523/19372)
回答No.3

>また、char **matrixと matrix[][3]は違うものですか? 違う物です。メモリ上のデータの配置を考えてみて下さい。 char **matrix; は 「どこかにcharへのポインタがあって、matrixは、その謎のポインタのアドレスを指してるポインタ変数」 です。 char matrix[][3]; は 「要素数が3の1次元配列(つまりcharが3個並んだ配列)が、(何個か不明だが)たくさん並んだ配列」 です。 char *matrix[3]; は 「charへのポインタが3つ並んだ(つまり、どこかを指すアドレスだけが、3つ並んでる)配列」 です。 どれも「値を取り出す時に、同じ書き方が可能」ですが「実際に値を取り出す方法」は違っています。

  • Tacosan
  • ベストアンサー率23% (3656/15482)
回答No.2

・T ** は「T型へのポインタへのポインタ」 ・T [][3] は「T型の大きさ 3 の配列の (大きさが未定の) 配列」もしくは (関数の引数宣言では配列が自動的にポインタに変換されるので) 「T型の大きさ 3 の配列へのポインタ」 なので, この 2つは別物です. しいていうと「int へのポインタ」と「double へのポインタ」くらい違うと思っていい. 余談ですが, 使い勝手を考えると 2次元配列を T matrix[5][5]; のように取るのはやめた方がいいと思う. 可能なら T **matrix; ととった上で動的に取る方があとで便利.

  • massano1
  • ベストアンサー率40% (4/10)
回答No.1

???部分は return keisan2(dat, matrix); です。 >また、char **matrixと matrix[][3]は違うものですか? コンパイル時にプロトタイプ宣言と変数定義が違った場合は エラーになります。変数定義で char *matrix[3]; と書いた場合は「**matrix」でも通りますが、ミスが見つけにくく なるので書かない方が無難だと思います。

関連するQ&A

  • 配列のポインタに渡す引数

    2次元配列に値をつめて、char*[]に渡すための 引数XXXは、どう設定すれば、よいのでしょうか? a(work);で、問題ないのでしょうか? いまいちchar*とchar*[]の違いがよくわかりません。 void main { char work[3][5]; sprintf(work[0], %s, "abc"); sprintf(work[1], %s, "def"); sprintf(work[2], %s, "ghi"); a( XXX );←ここの引数 } int a( char* [] ){ }

  • 2次元配列とポインタの引数受け渡しについて

    2次元配列を関数に渡すときは、引数に渡す2次元配列と同じサイズを指定、もしくは2次元目のサイズのみ合わせて渡す方法がありますが、両方とも違うサイズで同じ関数を使いたいです。 最初は中身が同じで引数で受け取る2次元配列のサイズだけ、それぞれに合わせた引数を持つ関数を2つ作っていたのですが、なんだか冗長な気がしました。 そこで、2次元配列の先頭ポインタとサイズを受け取るようにすればいいのかと思い、テストとして次のプログラムを作成してみました。 #include <stdio.h> void func(unsigned char *a, int y, int x); int main(void) { unsigned char a[10][10]; func(a, 10, 10); printf("%d\n", a[7][4]); return 0; } void func(unsigned char *a, int y, int x) { int i, j; for (i = 0; i < y; i++) { for (j = 0; j < x; j++) { *(a + i*y + j) = i * j; } } } もちろんこれでも動くのですが、やはりこういう書き方はルールにはないので、コンパイルで警告が出ます。 a.c: In function ‘main’: a.c:10: warning: passing argument 1 of ‘func’ from incompatible pointer type a.c:4: note: expected ‘unsigned char *’ but argument is of type ‘unsigned char (*)[10]’ このような書き方はやはりやめたいいのでしょうか。 また、その際はサイズ別に関数を作るしかないのでしょうか。 他にいい方法があれば教えていただけると助かります。

  • 二次元配列に関する質問です。

    一次元配列はわかるのですが二次元配列になると、わからない時があります。 <ソース> #include<stdio.h> int main() { int dat[2][5]={1,2,3,4,5,6,7,8,9,10}; int i; int j; for(i=0;i<2;i++){ for(j=0;j<5;j++){ printf("dat[%d][%d] %d\n",i,j,dat[i][j]); } } return 0; } このプログラムでわからないのは、 int dat[2][5]={1,2,3,4,5,6,7,8,9,10};の部分です。 普段は、int dat[2][5]={{1,2,3,4,5}, {6,7,8,9,10}, }; という使い方をしているのですが・・・。 どうちがうのでしょうか?

  • ポインタのアドレスについて

    こんばんわ。 以下のようなchar型の配列を直接Fooにキャストして利用したいのですが、 Foo構造体のdataにはint型の配列として利用したいのですが可能でしょうか? char型の配列を直接Fooにキャストした後にdataの部分を操作すれば 可能かと思っていたのですがうまくいきません。 foo->data=new int*[2]; としてしまうとbytData[8]が破壊されてしまいます。 このような方法は無理でしょうか? struct Foo {    int   tenmp ;    int   count ;    int**  data ; } ; char bytData[ 4 + 4 + 8 ] = { 1, 0, 0, 0,                 2, 0, 0, 0,                 3, 0, 0, 0,                 4, 0, 0, 0, } ; int _tmain(int argc, _TCHAR* argv[]) {    Foo* foo ;    foo = reinterpret_cast< Foo* >( bytData ) ;    foo->data = (int**)&bytData[ 8 ] ; // ここがダメ。    printf( "%d\n", *foo->data[ 0 ] ) ; // 3    printf( "%d\n", *foo->data[ 1 ] ) ; // 4    return 0 ; }

  • ポインタについての質問など

    (1) プログラム引数を取る時の記述ですが…. (int argc, char *argv[]) (int argc, char **argv) 本によって記述がまちまちなんです. これらはどう違うのでしょうか? 特に後者の解釈の仕方がいまいち分からないので教えてください. 配列になってないように見えるのですが…. (2) 後者の記述(int argc, char **argv)で書かれたプログラムで ./program.exe okwave と引数を取ったとき,okwaveのoからeまでをfor文やwhile文でたどって何らかの処理をしたいのですが,どうすればいいのでしょうか? (3) ポインタには関係ありませんが,Windowsでncursesは使えないのでしょうか?

  • 「動的確保した2次元配列のメモリ解放」を関数化したい

    質問タイトルの通りですが、 「動的確保した2次元配列のメモリ解放」をC言語で関数化したいと思っています。しかし、関数の引数には動的確保した配列の先頭アドレスのみ渡す形にしたいです。そのような場合の関数化は可能ですか? どうもうまくいかず、困っています。 以下、具体的に、サンプルソースを記述します。 わかる方、よろしくお願いします。 //====================================================// #include<stdio.h> unsigned char** AllocByteArray2d(int column, int row); void FreeByteArray2d(unsigned char** box); int main(voidls){ unsigned char array**; array = AllocByteArray2d(2, 3); FreeByteArray2d(array); return 0; } unsigned char** AllocByteArray2d(int column, int row){ unsigned char* box; box = (unsigned char**)malloc( sizeof(unsigned char*)*column ) int i; for(i=0; i<column; i++){ box[i] = (unsigned char*)calloc( row, sizeof(unsigned char)); if(box[i] == NULL) exit(EXIT_FAILURE); } return box; } //引数では配列の先頭アドレスだけ渡す形にしたい void FreeByteArray2d(unsigned char** box){ //ここをどう書いたらいいかわからない }

  • ポインタ配列

    "one","two","three","four","five","six","seven","eight","nine","ten" のポインタ配列の文字列を、ASCIIコード順に並べ変えようと思ったのですが、 もうどこが間違っているかさえわからないぐらいになってしまいました。 まだまだはじめたばかりなもので、わからないことだらけなんで、 できるだけわかりやすい説明おねがいします。 関数の引数に問題があるのじゃないかと思ったのですが、 何かいいアドバイスありましたら、お願いします。 #include <stdio.h> /* 関数のプロトタイプ宣言 */ int strmp(char *,char *); void cpy(char *,char *); int main (void) { /* ポインタ配列の定義 */ char *x[10]={"oneee","twooo","three","fourr","fivee","sixxx","seven","eight","ninee","tennn"}; /* ポインタのポインタの定義 */ char **pp=x; char k[100]; char *p=k; int i,t,a,b,c,d; a=0; /* ポインタ配列を自作関数を使って、ASCIIコードの大きいほうからに並び替える */ for(i=0;i<9;i++) { for(t=1;t<10;t++) { a=strmp(*(pp+i),*(pp+t)); if(a<0) { cpy(p,*(pp+i) ); cpy(*(pp+i),*(pp+t) ); cpy(*(pp+t),p); } } } for(i=0;i<10;i++) { printf("%s ,",x[i]); } printf("\n"); return 0; } /* 文字の比較をする関数 */ int strmp(char *x,char *y) { int i; for(i=0;*(x+i)==*(y+i);i++) { if( *(x+i)=='\0') { return 0; } } return *(x+i)-*(y+i); } /* 文字をコピーする関数 */ void cpy(char *a,char *b) { int i; for(i=0;*(b+i)!='\0';i++) { *(a+i)=*(b+i); } *(a+i)='\0'; }

  • ポインタ配列の開放について

    いつもお世話になっております。 C++言語初心者です。 ポインタ配列の開放(delete)について質問です。 ※includeは省略します。 int main(){   int *a[10];   for(int i=0;i<10;i++){     a[i]=new int[5];   }   delete[] *a;   return 0; } ポインタ配列を開放する場合、 上記のような書き方で正しいのでしょうか? ただ、上記のような記述方法が間違っている場合、 for(int i=0;i<10;i++){   delete[] a[i]; } とやるのはスマートでない気がするので、 もし他に方法がありましたらお願いします。

  • 配列のポインタ配列のポインタから元の配列を参照する方法について

    C初心者です。下記の様に配列のポインタ配列を作って、そのポインタ配列のポインタを返すコードを書いて、main関数で元の配列の値を参照したいのですが、上手く参照できずに困っています。下記のコードの問題点も含めて、配列のポインタ配列のポインタから、元の配列の値を参照する方法を教えてください。お願い致します。 short int *motion_data(void) { short int data1[5][7] = { {2377,2174,0,0,0,0,0}, {2377,2377,2784,2648,2648,2648,2377}, {2377,2377,2784,2648,2648,2648,2377}, {2377,2377,2377,2377,2377,0,0}, {2377,2377,2377,2377,2377,0,0}, }; short int data2[5][7] = { {2377,2174,0,0,0,0,0}, {2377,2377,2919,2784,2784,2784,2377}, {2377,2377,2919,2784,2784,2784,2377}, {2377,2377,2377,2377,2377,0,0}, {2377,2377,2377,2377,2377,0,0}, }; short int *po_data[2]; po_data[0] = data1[0]; po_data[1] = data2[0]; return *po_data; }

  • ポインタ配列について

    /************配列 change1.c ***********/ #include <stdio.h> void change(char *c) { c[0]='a'; c[1]='b'; c[2]='c'; } int main(int agrc, char **agrv) { change(*++agrv); printf("%s",*agrv); return(0); } /**********ポインタ change2.c ***********/ #include <stdio.h> void change(char *c) { c="abc"; } int main(int agrc, char **agrv) { change(*++agrv); printf("%s",*agrv); return(0); } ********************* この2つのプログラムchange1.c,change2.cにおいて、次のようにしたとき結果がこうなります \change1.exe 123 abc \change2.exe 123 123 change2.c において、ポインタでの文字の格納 c="abc"; は何故実行されないのですか?

専門家に質問してみよう