• ベストアンサー

多次元配列の引渡しについて

メイン関数と 副プログラム(?)間での  三次元配列の数値の引渡しは可能なのでしょうか? 今の私のプログラムだと どうもうまく引き渡されていないようなのです。初心者のため いきづまってしまいました。どなたか分かる方 教えていただけると助かります。

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

  • ベストアンサー
  • BLUEPIXY
  • ベストアンサー率50% (3003/5914)
回答No.4

>行列aの全ての要素に1を足して返させる //別のやり方のサンプルを作ってみました。 #include<stdio.h> #define n 2 void add1ToA(double *d, double*s, int size){ //先頭のアドレスと配列のサイズで処理 int i; for(i=0;i<size;i++) *d++ =*s++ + 1.0; } void printA(double a[n][n]){ int i, j; for(i=0;i<n;i++){ for(j=0;j<n;j++){ printf("%f ",a[i][j]); } printf("\n"); } } int main(void){ double a[n][n],c[n][n]; int i,j; for(i=0;i<n;i++) for(j=0;j<n;j++) a[i][j]=0; //初期化 add1ToA(&c[0][0], &a[0][0], sizeof(a)/sizeof(double));// c ← a + 1 : a は、変更しない printA(a); printf("\n"); printA(c); return 0; }

donntakosu
質問者

補足

本当に毎回ご親切な回答 ありがとうございます! サイズというものを利用するのですね!ということは 三次元でも、 同じようにやればよいのでしょうか? また、今回は例として ”全要素に1足す” というプログラムを書き ましたが、もっと複雑な計算も 上記の書き方を 応用すればよいのでしょうか? たびたびの質問すみません。 

全文を見る
すると、全ての回答が全文表示されます。

その他の回答 (7)

  • BLUEPIXY
  • ベストアンサー率50% (3003/5914)
回答No.8

#7補>sizeof(doubleの配列名)/sizeof(double)というのは どのような意味 sizeofは演算子で、オブジェクトのサイズを返します。 オブジェクトとは変数や構造体や型や構造体の型とかです。 doubleが8バイトで表されるとしたら sizeof(double) は、8になります。 double a[10]; の時 sizeof(a) は、80バイトになります。 上記の時 なので、sizeof(a)/sizeof(double)は、80/8=10 となって 配列のサイズを求めていることになります。 こうした手法は、 a[]={1,2,3,4}; とか配列のサイズを明記しないで初期化による自動的にサイズを決めた様な場合に、サイズを直接記した場合と違ってサイズを計算で求めているので、変更に際して意識しなくていいことがメリットです。 実際に、sizeofの結果を表示するようなプログラムを作って試してみるといいでしょう

donntakosu
質問者

お礼

今回  何度もご親切な回答 本当にありがとうございました! とりあえず今回質問した内容については 理解することが出来たかと 思いますが、まだ初心者なため 一つ分かったかと思うと 又別の 壁にぶち当たるということがたびたびのため、またいずれ 一人では 解決できないことが出来たときは こちらで質問させていただく かもしれません(^^ゞ  今回は本当にたびたびありがとうございました!

全文を見る
すると、全ての回答が全文表示されます。
  • BLUEPIXY
  • ベストアンサー率50% (3003/5914)
回答No.7

>サイズというものを利用するのですね! う~ん、う~ん(-~-); double *p; のような並びとして処理するからサイズが必要になるのです。 #5でもおっしゃっているように a[x][y] の様な場合、ポイントする位置を計算するには a[][y]のようにx は無くても(?)いいですが、 [x][y]の様にアクセスするには y は必要です。 つまり折り返す場所がわからんということですね。 a[x][y]とすればそれぞれの場所は a[x][y]でアクセスできますが、 a[x][y]を*pで受けるということは、 a[x*y]で受けるようなものです。 全体を1つの並びとして同じ処理をするなら、先頭のアドレスと、全体のサイズがわかれば処理できます。 そういうことです。 ケースバイケースで使うといいと思います。 >三次元でも、同じようにやればよいのでしょうか? 同じようなケースの場合同じようにできます。 >もっと複雑な計算も、上記の書き方を、応用すればよいのでしょうか? そうですね、どのようなケースでどの書き方が使えるかは一概には言えないように思いますので明言はできませんが #1の様に配列として扱う #4の様に[ ]を使わないように扱う あるいはその混用というようにプログラマのやりたいようにできます。 要は、今扱っているポイント先が何を表しているのかちゃんと把握していればいいのです。

donntakosu
質問者

お礼

(訂正です!) size じゃなくて sizeof でしたね(^^ゞ

donntakosu
質問者

補足

とても 分かりやすかったです!!ありがとうございます! *p++ という使い方と意味を 今回ここで教えていただいて 初めて知りました! ちなみに size(配列名)/size(double)というのは どのような意味を もつのでしょうか? size(配列名) とだけ記述するのとは何がちがってくるのでしょう?

全文を見る
すると、全ての回答が全文表示されます。
  • BLUEPIXY
  • ベストアンサー率50% (3003/5914)
回答No.6

>> 配列名は、ポインタではなくアドレス定数です。 >要するに「ポインタ」ですよね。。。 要するに「ポインタ」と言ってしまっては語弊があるので、 「アドレス定数」と言っております。 ポインタ演算ができることとポインタとは異なると思っております。 例えば 配列名を使って*(array + 5)のようなことはできても ポインタは++でポイントする位置をインクリメントできますが、当然配列名ではできません。 まあ、何を中心にして言っているかで違うのだということだと思いますが。

全文を見る
すると、全ての回答が全文表示されます。
  • ency
  • ベストアンサー率39% (93/238)
回答No.5

配列=ポインタという理解は間違いです。 配列はコンパイラによって「先頭要素を指すポインタ」に読み替えられるんです。 つまり、 int hoge[30]; と定義した場合、メモリ上には int型 30個分の領域が確保されることになりますが、式の中で「hoge」と使った場合には、&hoge[0] と等価、つまり配列 hoge の先頭要素 hoge[0] を指すポインタとして扱われるわけです。 # ですので、BLUEPIXYさんの No2 での以下の回答は、はずしていると思うん # ですが…(??) # # > 配列名は、ポインタではなくアドレス定数です。 # # もっと細かいことを言えば、配列名は左辺値として使用できない # (値を代入できない) とか、通常のポインタが間接参照なのに対して # 配列名は直接参照であるとか、いろいろあるんで面倒くさいんですけど、 # 要するに「ポインタ」ですよね。。。 int hoge[30]; ⇒ hoge は &hoge[0] に読み替えられる。  このとき読み替えられる型は int を指すポインタ (int *型) という基本がわかっていれば、あとは同じことです。 int piyo[10][20][30]; ⇒ piyo は &piyo[0][0][0] に読み替えられる。  このとき読み替えられる型は「『intの配列(要素数30)』の配列(要素数20)」を指すポインタ (int (*)[20][30]型) となります。 # どうしてこのようになるのか、ご自分でじっくりと考えてみてください。 ちなみに、「配列」→「ポインタ」の読替えは再帰的には行われません。 ですので、「配列の配列」→「配列を指すポインタ」にはなりますが、そこからさらに「ポインタを指すポインタ」にはなりません。 さて、前置きが少々長くなりましたが、関数の引数の配列を渡す場合には、必ずポインタに読み替えられた形で渡ることになります。 int hoge[30]; を関数 func1 の引数として渡したい場合、たとえば 「func1( hoge );」のようにコールしたい場合には、 void func1( int *p_hoge ); という型の関数を用意する必要があります。 同様に int piyo[10][20][30]; を関数 func2 に渡したい場合、たとえば「func2( piyo )」のようにコールしたい場合には、 void func2( int (*p_piyo)[20][30] ); という型の関数を用意してあげる必要があります。 なお、関数の仮引数に限り、ポインタ表記と配列表記は同じ意味を持ちます。 # 正直、こんな面倒な仕様があるために、配列とポインタに関する誤解が広まっている # 気がしなくもないんですけどね。。。 つまり、上記 func1() と func2() は以下のように書いてもまったく同じ意味になります。 〔func1() の定義〕 (1) void func1( int hoge_array[] ); (2) void func1( int hoge_array[30] ); /* (2) の場合、配列要素数 30 は無視されます */ 〔func2() の定義〕 (1) void func2( int piyo_array[][20][30] ); (2) void func2( int piyo_array[10][20][30] ); /* (2) の場合、配列要素数 10 は無視されます */ 通常は、配列の定義・宣言いずれもポインタの定義・宣言と異なりますので、ご注意ください。 # int hoge[30]; # # と # # int *hoge; # # が違うことは、改めて申し上げる必要もありませんよね? 細かい処理の話は、BLUEPIXYさんにお任せします。 # あ…肝心なところ逃げた (?) とりあえず、ご参考まで。。。

donntakosu
質問者

補足

とてもご親切な回答なのに 読んで分かりそうで分からず 混乱してくる自分が情けないです(苦笑)しかし ありがとうございます! ええと、BLUEPIXYさんの書いてくださった通りにやってみたら ついに 値がきちんと 引き渡されたように見えたのですが、 三次元の配列を引き渡したい場合、 int piyo[10][20][30] は、func(&piyo[0][0][0],sizeof(piyo)/size(double))でコールしたいとする時、 void func(int *ppiyo, int size)-(1) ではダメなのですか? それと、void func2( int (*p_piyo)[20][30] ); と書くのと (1)式 との違いはどのようなことなのでしょう?また、(*p_piyo)[20][30] とは、どんな意味をもち、プログラム中で、数値を代入させたりする 計算式中では どのように用いればよいのでしょう? 通常通り for(i=0;i<n;i++){ for(j=0;j<n;j++){ for(k=0;k<n;k++){ (*p_piyo)[20][30]=1; } } }などとつかうのでしょうか?違いますよね(^^ゞ 質問攻めですみません・・・

全文を見る
すると、全ての回答が全文表示されます。
  • BLUEPIXY
  • ベストアンサー率50% (3003/5914)
回答No.3

#2礼>できれば三次元の配列に収めた数値を 三次元のまま 引き渡せるといいのですが・・・w それができることは、すでに#1で示したつもりです。 #2補> 補足されたプログラムのやりたいことは何でしょうか? よろしければ、やりたいことについて補足して下さい。 間違ったプログラムだけ示されても、意図が正しく伝わりません。 配列aを初期化したものをfuncで全ての要素について+1するというような意味なのでしょうか (もしそうなら、全然違います) for(i=0;i<n;i++){ for(j=0;j<n;j++){ b[i][j]=a[i][j]+1; return b[i][j]; } } では、ちょっと考えてみればわかるように、 i:0,j:0でリターンしてしまいますから いつでもa[i][j]+1の値が返されるだけです。 また、 return b[i][j]; で返されているのは、b配列の中の1つの要素の値であって、 b配列そのものではありません。 もし、a配列を処理した結果をc配列に入れたいというのなら aとcをfuncに渡して、そこで処理すれば良いです。 #1でも示したように、#1の様に配列を渡した場合、 受けた配列の処理はそのまま、その配列をいじることになります。

donntakosu
質問者

お礼

そうですね、すみません、私の記したプログラムは 行列aの全ての要素に1を足して返させる と試したかったのですが・・・ そうですか!このようなreturnの仕方は iとjの全ての組み合わせに対して値を返してくれるのだと思ってやってみてしまったのですが これだと i=j=0  の値しか返さず まったくの間違いなのですね! どうもありがとうございます!行列の全ての成分を同じ値に設定したため 間違いに気づきませんでした・・・。 aとcをfuncの引数とさせればいいのですね。試してみます!

全文を見る
すると、全ての回答が全文表示されます。
  • BLUEPIXY
  • ベストアンサー率50% (3003/5914)
回答No.2

>配列というのはもうポインタ変数になっている 配列名は、ポインタではなくアドレス定数です。 >ポインタとしての引渡しは一次元でしかできないのでしょうか?? もちろん、2次元とかでもできますよ。 一次元のポインタとして受ける場合は、 *pointerでいいと思います。 その場合(2次元のポインタを1次元で受ける場合)は、ポインタ計算に注意してやらないといけません。 2次元のポインタとして受ける場合は、 (*pointer)[size] 見たいな感じでいいと思います。 サンプルで配列として書いたのは、わかりやすさのためです 副プログラムでの変更が主プログラムに及んでいることから、 コピーされた配列というわけではないのがわかると思います。 難しいポインタの宣言をするときは、 typedefで適当に型を作って一段ずつやってやるとわかりやすくなります。 >tolower は、ctype.h で定義されている標準関数です。

donntakosu
質問者

お礼

BLUEPIXYさんの回答 とても詳しくて ありがたいのですが 私 実はまだかなり初心者で ポインタについても 本当に分かっているか否か 疑わしいレベルです(^^; できれば三次元の配列に収めた数値を 三次元のまま 引き渡せると いいのですが・・・w

donntakosu
質問者

補足

お返事遅くなりすみません! 三次元の配列を引き渡す際、例えば、以下のようなプロムで配列bを 引き渡したい場合、 #include<stdio.h> #define n 2 double func(a[n][n]){ int i,j; double b[n][n]; for(i=0;i<n;i++){ for(j=0;j<n;j++){ b[i][j]=a[i][j]+1; return b[i][j]; } } } main() { int i,j; double a[n][n],c[n][n]; for(i=0;i<n;i++){ for(j=0;j<n;j++){ a[i][j]=0; c[i][j]=func(a); } } return 0; } というように 副プログラムのreturn の後ろにおくことは可能なのでしょうか?実際上の簡単なプログラムを作って実行してみたところ 確かな実行結果が得られたので 本番のプログラムでも上のようにして 引き渡してみたのですが 引き渡す前はきちんとした値を持っていることを確認できたにも関わらず、引き渡した後の中身を見てみると 全て ゼロになっており、うまく引き渡されていないようなのです。 また、return の後ろにb[i][j][k]のような多次元配列をおいて それをさらにforループの中に置く というような例を見たことがないため このような使い方を本当にしていいものか 疑問もあります。結局そこのところを いまだにどうしたらいいのか困っている次第なのです(汗)

全文を見る
すると、全ての回答が全文表示されます。
  • BLUEPIXY
  • ベストアンサー率50% (3003/5914)
回答No.1

//どんな風に書いているのかわからないんですが、 //どんな風にやってるんですかね? //とりあえずのサンプル #include <stdio.h> #include <ctype.h> void tolowerD3(char data[3][3][3]){ int x, y, z; for(x=0;x<3;x++) for(y=0;y<3;y++) for(z=0;z<3;z++) data[x][y][z] = tolower(data[x][y][z]); } void main(void){ char dim3[3][3][3]={ {{'a','b','c'},{'A','B','C'},{'C','B','A'}}, {{'x','y','z'},{'X','Y','Z'},{'Z','Y','X'}}, {{'L','m','n'},{'N','m','L'},{'M','n','L'}}, }; int x, y, z; tolowerD3(dim3); for(x=0;x<3;x++){ printf("{"); for(y=0;y<3;y++){ printf("{"); for(z=0;z<3;z++){ printf("%c,", dim3[x][y][z]); } printf("},"); } printf("},\n"); } }

donntakosu
質問者

補足

お返事どうもありがとうございます!私は 数学の行列の計算を C言語で行っており 要は メイン関数のほうで数を 定義した行列を、 副プログラムのほうへも 引き渡したいのですが、 どうもうまくいってないようなのです・・・配列というのは もう ポインタ変数になっていると思っていたのですが それともポインタ としての引渡しは 一次元でしかできないのでしょうか?? それと 教えてくださったプログラムの中の 8行目の tolower というのは もともとC言語で使える関数か何かでしょうか??

全文を見る
すると、全ての回答が全文表示されます。

関連するQ&A

  • 2次元配列

    2次元配列は宣言して生成しますが配列名が異なる配列を例えば100個用意するにはいちいち宣言していたらすごいプログラム量になるので何かいい方法はないでしょうか?付け足しで指定した個数(例えば100個)分名前の異なる2次元配列を生成するには? java初心者なのでサンプルプログラムがあるとありがたいです。よろしくお願いします。

  • 多次元の配列を[ ]で括って見やすくトレースするには?

    多次元の配列を[ ]で括って見やすくトレースするには? 何次元か特定される配列ならばforなどで次元の数だけ繰り返せばできるとは思うのですが そうでないときにも [ [ [a,b,c,...],[],[],...],[],[],... ] のように隣り合う要素(配列)との切れ目が見やすいようにトレースする方法はありますか? プログラムには影響しませんが、トレースすると1次元の配列と同じように , だけで区切られてトレースされてしまい見にくいですので 配列が何次元か返させる関数など書ければ良いと思うのですが FlashPlayer10、ActionScript3.0です 質問の意味理解していただけるでしょうか お願いします

    • ベストアンサー
    • Flash
  • 二次元配列が、勝手に一次元配列になってしまう

    Excelのマクロで、二次元配列を格納したバリアント型を戻り値とする関数を作ったのですが、… 二次元型配列のひとつの要素数が1の時、受け取ったバリアント型変数は、一次元配列になっています。 列ベクトルなら、それもありかな~と思うのですが、なんで、行ベクトルまで、一次元配列にするんだよ~って、困っています。 シートから関数を呼んだ場合は、列ベクトルは列ベクトル、行ベクトルは行ベクトルとして、表示されるので、マクロの中で関数を呼び出した場合も、行列の情報を保持できる方法があるんじゃないかと思ったのですが。 どなたか、ご教示頂けるとありがたいです。 よろしくお願いします。

  • 多次元配列なんですが・・・

    初心者です。多次元配列をつかって縦の一列目と横の一列目だけに要素を表示さてたいのですが、どのようなプログラムを組んだらいいのでしょうか。友達に「triMatrix」というのを使ったらどうかといわれたのですが、いまいち分かりませんどなたか助言をお願いします。

  • 2次元配列でエラーがでます。

    VC++を使ってプログラムを書いています。2次元配列で配列を大きくするとエラーが出てしまいます。1次元配列の場合は今のところ特にエラーは出ない感じです。プログラムにもよりますが、小さい配列でa[300][300]くらいでエラーが出てしまいます。だいたい配列をa[10000][10000]くらい取りたいのですが。このエラーを解消する方法はないでしょう?

  • 二次元配列について

    高校の課題研究で、タイピングソフトを作ることになったのですが 二次元配列で、配列内の文字列をランダムで一つ表示するものを作りたいのですが 全然分かりません^^; プログラムを教えてくださる方いらっしゃいましたら 教えて貰えますとありがたいです><

    • ベストアンサー
    • Java
  • 2次元配列の配列

    VisualBasic.NETでプログラムを作っているのですが、2次元配列の配列で行き詰って困っています。 配列1~3を別に定義して、その2次元配列を配列Xという配列にひとまとめにしたいのですが、エラーが出てしまいます。 エラー内容は「配列初期化子の次元が少なすぎます」で、場所は配列Xの第1要素です。 配列1~3以降もどんどん配列を追加していく予定なので、なるべく以下の方法で書いていきたいのですが、解決法はないでしょうか? また、他にいい方法があればご教授ください。 ソースです。 ---------------------------------------- Public 配列1(,) As Integer = _ { _ {1, 1, 1}, _ {1, 1, 1}, _ {1, 1, 1}, _ {1, 1, 1} _ } Public 配列2(,) As Integer = _ { _ {2, 2, 2}, _ {2, 2, 2}, _ {2, 2, 2}, _ {2, 2, 2} _ } Public 配列3(,) As Integer = _ { _ {3, 3, 3}, _ {3, 3, 3}, _ {3, 3, 3}, _ {3, 3, 3} _ } Public 配列X(,)() As Integer = { _ 配列1, _     ←ここにエラーが出る 配列2, _ 配列3 _ } ---------------------------------------- 回答よろしくお願いします。

  • 2次元配列を多次元配列にする。

    2次元配列を多次元配列にする。 PHP5で 2次元目はすべて同じキーの2次元配列を 2次元目のキーごとの内容を共通項にまとめて、 多次元配列にする方法を教えてください。 キーの数は膨大なので、関数の再帰呼び出し で、きれいに処理したいのです。 説明文では説明しきれないので、 やりたいことは↓の通りです。 array[0] = array([one] => "あ", [twe] => "う" [three] => "き"); array[1] = array([one] => "あ", [twe] => "う" [three] => "く"); array[2] = array([one] => "あ", [twe] => "え" [three] => "け"); array[3] = array([one] => "あ", [twe] => "え" [three] => "こ"); array[4] = array([one] => "い", [twe] => "お" [three] => "さ"); array[5] = array([one] => "い", [twe] => "お" [three] => "し"); array[6] = array([one] => "い", [twe] => "か" [three] => "す"); array[7] = array([one] => "い", [twe] => "か" [three] => "せ"); という配列があったら、これを↓のようにしたいです。 array( [あ] => array( [う] => array ("き", "く") [え] => array ("け", "こ") ) [い] => array( [お] => array ("さ", "し") [か] => array ("す", "せ") )   ) どうぞよろしくお願いいたします。

    • ベストアンサー
    • PHP
  • 多次元配列の一次元目の最大値の求め方

    多次元配列の一次元目の最大値の求め方 下記のような多次元配列(ちなみに、これって二次元配列ですか?)があるとき、 常に、「一次元目の最大値+1」を返すようにしたいのですが、 どうすればよいのでしょうか? $data[0][0]とか$data[1][0]とか$data[2][0]とかの最大値の意味です。 下記の例でいくと、一次元目の最大値が3なので、数値の4を返したいのですが…、 ■$data 1,0,A1,B1,C1 2,5,A2,B2,C2 3,0,A3,B3,C3 3,2,A4,B4,C4

    • ベストアンサー
    • PHP
  • 3次元配列から2次元配列への代入

    C言語初心者です。 詳しい方、宜しくお願い致します。 下記のような三次元配列(Sanjigen[2][5][5])があります。 ダンプしたもので見難くてすみません。 00FFBCBC [0][0][0] 01 02 03 04 05 00FFBCC1 [0][1][0] 06 07 08 09 10 00FFBCC6 [0][2][0] 11 12 13 14 15 00FFBCCB [0][3][0] 16 17 18 19 20 00FFBCD0 [0][4][0] 21 22 23 24 25 00FFBCE4 [1][0][0] 26 27 28 29 30 00FFBCE9 [1][1][0] 31 32 33 34 35 00FFBCEE [1][2][0] 36 37 38 39 40 00FFBCF3 [1][3][0] 41 42 43 44 45 00FFBCF8 [1][4][0] 46 47 48 49 50 このデータ(Sanjigen[2][5][5])を、二次元配列にしまう方法をご教授ください。 Nijigen1[5][5]には三次元配列のデータ(1~25)と(26~50)をアンドしたデータを格納します。 Nijigen2[5][5]には三次元配列のデータ(1~25)と(26~50)をオアしたデータを格納します。 下記は自分の作ったプログラムですが、うまくいきません。 char Sanjigen[2][5][5]; char Nijigen1[5][5]; char Nijigen2[5][5]; void get_data( void ) { char i; for( i=0; i<8; ++i ){ Nijigen1[i] = Sanjigen[0][i] & Sanjigen[1][i]; Nijigen2[i] = Sanjigen[0][i] ^ Sanjigen[1][i]; } } 説明わかりにくくて申し訳ありません。 宜しくお願い致します。