• ベストアンサー

引数に二重配列のある関数について

void calc(int *a,int b,int c){ a[0]=b+c; a[1]=b-c; } void main(void){ int x[2]; int y=2,z=5; calc(x,y,z); printf("x[0]=%d,x[1]=%d\n",x[0],x[1]); } 上のように引数が普通の配列の関数ならできるのですが, 引数が下のような多重配列になるとエラーが出てしまいできません。 void keisan(int **a,int b,int c){ a[0][0]=b+c; a[0][1]=b-c; a[1][0]=b*c; a[1][1]=b/c; } void main(void){ int x[2][2]; keisan(x,6,2); printf("x[0][0]=%d,x[0][1]=%d\n",x[0][0],x[0][1]); printf("x[1][0]=%d,x[1][1]=%d\n",x[1][0],x[1][1]); } 引数に多重配列を使った場合の関数の作り方について教えてください. お願いいたします.

noname#3351
noname#3351

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

  • ベストアンサー
  • leaz024
  • ベストアンサー率75% (398/526)
回答No.3

 2次元配列というのは、2つの添え字を使って表のイメージでデータを扱えるので大変便利なのですが、結局メモリの中では1次元配列と同じように、直線的にデータが配置されています。  つまり   int x[2][2];   x[0][0] = 1; x[0][1] = 2;   x[1][0] = 3; x[1][1] = 4; と定義されているとすると、メモリの中では、   x   1 2 3 4 となっています。  ためしに x[0][2] を表示してみると、3 が表示されます。  この2次元配列xは、1次元目(1番右)の要素数が2個であると宣言されているので、x[1][0] とアクセスするだけで、xから3番目のデータを取り出すことができるわけです。  ところが関数keisanで宣言されている int **a には、この「要素数の情報」がないため、 a[1][0] がメモリのどこにアクセスすればよいのか分からないので、エラーとなってしまうのです。  これを解決するには、2次元配列を受け取る変数の宣言に、1次元目の要素数情報を与えてやればよいわけです。宣言方法は次の通りです。   void keisan(int a[ ][2], int b, int c);  仮引数の宣言で配列を宣言しても、同等の配列へのポインタになるので、配列が丸々コピーされることはありません。  2次元目の要素が空になっていますが、配列が用意されるわけではないので、ここには2を入れても全く意味がありません。入れても無視されます。  ちなみにsssoheiさんの int a[2][ ] や、int a[2][ ] は文法違反です。 また int *a[2] という宣言は、ポインタ配列を受け取る場合の書き方で、やはりこの場合はエラーになります。  3次元以上の配列の場合でも、考え方は同じです。ただし要素数を省略できるのは、1番左だけということを覚えておいてください。  下記は、int x[2][3][4]; と宣言された変数aを受け取るための引数の宣言です。   void func(int a[ ][3][4]);

その他の回答 (3)

noname#9538
noname#9538
回答No.4

int* a[2] は駄目だけど, int (*a)[2] なら OK (もちろん int a[][2] でも OK) int型の大きさ 2の配列 2個からなる二重配列 x[2][2] の配列名 xを単独で書いた時の型は int** 型ではなく, int (*)[2] または int a[][2] 型 なのでこう書かなければいけない. int** はint型の値を指すポインタのポインタの型, int(*)[n] はint型の値をn個並べた配列へのポインタの型, で両者は全く異なる型である. ついでに,main の返却値は void でなく int が正しいと思います。

  • sssohei
  • ベストアンサー率33% (33/98)
回答No.2

int ** ではコンパイラはどのくらいの大きさの 配列なのかが分からないので、コンパイルエラーが出ます。 そこで、 int a[2][] のように、記述する必要があります。 三重の場合は int a[2][2][] の様に記述します。 もちろん、 int a[2][2] の様に記述しても構いませんし、 int* a[2] でも大丈夫だと思います^^; 記憶の中のものなので、実際試してみてください^^;

noname#794
noname#794
回答No.1

コンパイルかけてみたところ、以下のようなエラーでした。 ==================================================================================== "test.c", 54 行目: 警告: 1 番目の引数は、プロトタイプ宣言の型と互換性がありません: プロトタイプ: pointer to pointer to int : "test.c", 41 行目 引数 : pointer to array[2] of int ==================================================================================== 関数のほうはintのポインタのポインタを引数として求めているのに、 mainはintの配列を引数として渡しているからこのエラーが出たのだと思います。 そこで以下のように関数の宣言を変えてみたところ、うまくいきました。 void keisan(int **a,int b,int c) ↓ void keisan(int a[2][2],int b,int c)

関連するQ&A

  • 2次元配列を引数とする関数について

    2次元配列を引数とする関数について 私は今、2次元配列を引数とする関数の表を作るという課題に取り組んでいます。 条件として、int a[数字][数字]={{1,2,3...}}という配列の宣言と同時の初期化は使わず、 関数内で表の値を代入し、値を表示する関数を作り、事実上二つの関数を作るというものです。 私は以下のようなプログラムを作り、動かしましたが、[数字][数字]=********のような本来 あるべき実行結果とは異なる数字の羅列が出てきてしまいました。 ↓ #include <stdio.h> void func(int a[][6]); void fund(int b[4][6]); void main(void) { int a[4][6]; fund(a); func(a); } void func(int a[][6]) { int i,j,b[4][6]; fund(b); for(i=0;i<4;i++)        { for(j=0;j<6;j++) { printf("a[%d][%d]=%d\n",i,j,a[i][j]); printf("\n"); } } } void fund(int b[4][6]) { int i,j; for(i=0;i<4;i++) { for(j=0;j<6;j++)          { scanf("b[%d]*[%d]=%d\n",&i,j,b[i][j]); } } } 本来の実行結果 1 2 3 4 5 6 2 4 6 8 10 12 3 6 9 12 15 18 4 8 12 16 20 24 紙にも書いて何回も見直しましたが、どこがおかしいのかわかりませんでした。 どうすれば良いのでしょうか? 何か良いアドバイスをよろしくお願いします。

  • 関数に配列を渡して値を変える

    関数に配列を渡して値を書き換えたいのですが、文字配列である char b[10]="abc"; の書き換えが綺麗にできません。 どのように書いたら綺麗にできますか? void hen(int *a, char *b,char **c){ *a=7; b[0]='d'; b[1]='e'; b[2]='f'; //こういう書き方なら渡せるけれどb[10]="def"; 見たいな書き方で一行で値を渡す方法はないものかな? *c="jkl"; } void main (void){ int a=5; char b[10]="abc"; char *c="ghi"; hen(&a,b,&c); printf("%d %s %s\n",a,b,c); }

  • 配列

    適当な記述ですが、次を見てください。 void roll(int *c) { int n, b2[8]; if(t<3) { for(n=0; n<8; n++) b2[n]=c[n]; for(n=0; n<8; n++) c[b2[n]]=7-n; for(n=0; n<8; n++) printf("%d",c[n]); printf("\n"); t++; roll(c); } else t=0; } int main() { int b[]={3,6,4,0,7,2,5,1}; roll(b); for(n=0; n<8; n++) printf("%d",b[n]); //36407251が表示されるようにしたい。 return(0); } rollが何の関数かは省略しますが、rollにmainのb(ポインタ?)を渡し、ある処理をして,それでmainに戻ってきた時にb[]を表示すると、36407251が表示されません。 ポインタを引数にするってことはポインタでさしてるとこをrollで操作してるわけですよね? そうすれば変わって当然だとはおもいます。 でも関数1で関数2に配列1を渡し、その関数2の中でで配列1の値が変化しても、元の関数1にもどれば配列1のまま変化していないようにするにはどうすればいいですか? やはり もう1つ配列を用意しなきゃだめなのでしょうか。

  • 関数の引数表記なしについて

    はじめまして。C言語初心者です。 質問させてください。 関数を宣言して引数を表記しないで使用することは可能なのでしょうか? またどのような場合に使用するのでしょうか? 例として以下コードになります。 ----------------------- #include<stdio.h> int test1(int a); void test2(int b); void main(){ int i = 0; int j = 0;       //この部分 i = test1; printf("%d\n", i);        //この部分 j = test2; printf("%p\n", j); } int test1(int a){ return a + 1; } void test2(int b){ printf("test"); } --------------------------- 出力結果を見ると関数のアドレスが帰ってくるように思われますが、詳細が分かりません。 詳しい方がいらしましたら教えてください。 宜しくお願いいたします。

  • 関数先にて配列の長さを取得する方法

    関数にて、引数にて渡された配列(ポインタ)から配列数を調べる方法はないでしょうか? #include <stdio.h> void test(unsigned int *p){ printf ("%d\n", sizeof(*p)/sizeof(p[0])); //結果 1 } int main(){ unsigned int hoge[] = {0x30, 0x31,0x32}; test(hoge); printf("%d", sizeof(hoge)/sizeof(hoge[0])); //結果3 return 1; } 上記コードの関数testの*pから配列の数3が抜き取りたいと思っております。 よろしくお願いします。

  • 引数のみで出力

    問題として main内部を変更してはならない。 関数sub()でmainのループと同じ出力するようにせよ。 ただし、関数subで引数以外の変数を宣言してはならない。 また、広域変数を追加してはならない。 となっていて、色々とforループで出力させようと 配列にしたりポインタにしたりしたのですが forのiに比例する配列をどう組めばいいのか、わからないです。。。 mainの出力は 1 8 15 22 29 36 となっています。 これをsubでもできるように設定するみたいです。 #include <stdio.h> #define MAX 7 void sub(int [MAX]); int main() { int i; int x[MAX]; for (i = 0; i < MAX-1; ++i) { x[i] = 7*i+1; } x[MAX-1] = 0; for (i = 0; x[i] > 0; ++i) { printf("x = %d\n", x[i]); } printf("print again\n"); sub(x); return 0; } void sub(int a[MAX]) { // a[6]=0 // MAX 7 a[MAX-1]=0; for(a[MAX-1];a[MAX-7]<=MAX-1;++a[MAX-1]){ //a[MAX-1] = 7*a[MAX-1]+1; printf("a[%d] = %d\n",a[MAX-1],a[MAX-7]); } }

  • VCで作ったDLL【否 .Net】 配列

    VCでDLLを作り、VBから呼び出しています。 今やりたいのは、Cで言えば void Calc(int a, int b, int x[]) {  x[0] = a + b;  x[1] = a - b;  x[2] = a * b; } int main(int argc, char *argv[]) {  int n[3];  Calc(8,1,n);  printf("%d %d %d\n",n[0],n[1],n[2]);  return 0; } と、いうことです。 関数Calcを__stdcallやdefファイルを使って呼び出せるようにし、VBから呼ぶのですが、うまくいきません(~~メモリが"written"になることは~~)。 VBでは Declare Sub Calc Lib "SimpleDll.dll" (ByVal a As Long, ByVal b As Long, ByRef x() As Long) …略… Dim x(3) As Long Call Calc(6, 4, x) …略… としています。 どうかお力添えを。

  • プログラミング(配列と関数の引数)

    a : ABCDE a : ABCDEFGH Len : 8 a : FGHIJ a : FGH a : FGH, c : FGH 上記のように表示されるプログラムを作りたいのですが、なかなかできません。下記のようなプログラムを作ったのですがどこが間違っているのかよくわかりません。分かる方、指摘をお願いします。 #include <stdio.h> void my_strcpy(char s[], char t[]); int my_strlen(char s[]); void my_strcat(char s[], char t[]); int main(){ char a[10]; char b[10] = "ABCDE"; char c[] = "FGH"; int len; my_strcpy(a, b); printf("a : %s\n", a); my_strcat(a, c); printf("a : %s\n", a); len = my_strlen(a); printf("Len : %d\n", len); my_strcpy(a, "FGHIJ"); printf("a : %s\n", a); a[3] = '\0'; printf("a : %s\n", a); if(strcmp(a, c) == 0){ printf("a : %s, c : %s\n", a, c); } int i, s, t; my_strcpy(a, b + 2); printf("a : %s\n", a); void my_strcpy(char s[], char t[]){ for (i = 0; t[i] != '\0'; i++){ s[i] = t[i]; } s[i] = '\0'; } int my_strlen(char s[]){ int i; for (i = 0; s[i] != '\0'; i++); return i; } void my_strcat(char s[], char t[]){ int i, j; for (i = 0; s[i] != '\0'; i++); for (j = 0; t[j] != '\0'; i++, j++){ s[i] = t[j]; } s[i] = '\0'; } }

  • 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]’ このような書き方はやはりやめたいいのでしょうか。 また、その際はサイズ別に関数を作るしかないのでしょうか。 他にいい方法があれば教えていただけると助かります。

  • 引数で指定された配列の要素数の取得

    どうもこんにちは。 C言語でプログラムを作成しています。 ある関数に配列を渡すことを考えていますが、渡した配列の要素数を取得する方法は何かありますか? 標準の関数を見ても、配列の先頭アドレスのポインタとともに、配列の要素数を渡しているものばかりで、配列のポインタを渡しているものは見かけません。 要素数があらかじめわかっていれば、それを引数の型に指定できますが、呼び出されるまで不明な場合はうまくいきません。 配列の要素数も引数として一緒に渡す必要がありますか? [作ってみたサンプル] #include <stdio.h> #include <stdlib.h> #include <string.h> // func1 と func2 をまとめられないだろうか。。。 void func1(int (*p)[10]) { ________int n = sizeof(*p) / sizeof((*p)[0]); ________int i; ________for (i = 0; i < n; i++) { ________________printf("%d\n", (*p)[i]); ________} ________printf("\n"); } void func2(int (*p)[5]) { ________int n = sizeof(*p) / sizeof((*p)[0]); ________int i; ________for (i = 0; i < n; i++) { ________________printf("%d\n", (*p)[i]); ________} ________printf("\n"); } int main(int argc, char *argv[]) { ________int ary1[10] = { 2, 4, 6, 8, 0, 1, 3, 5, 7, 9 }; ________int ary2[5] = { 3, 6, 9, 12, 15 }; ________func1(&ary1); ________func2(&ary2); ________return 0; }

専門家に質問してみよう