トップページ > 過去ログ > 記事閲覧
多次元配列の構造体のポインタを返す方法
名前:通りすがり 日時: 2008/02/25 00:02

例えばですが STest Test[2][2]; という構造体があって、 STest** Return() { return Test; }; と言う形で返したいのですが、 STest[2][2]' から STest**' に変換できません。 という形でエラーが出てしまいます。 わかりにくくて申し訳ありません。 エラーが出ずにすむ方法があればおしえていただきたく 思います。よろしくお願いします。

Page: 1 |

Re: 多次元配列の構造体のポインタを返す方法 ( No.1 )
名前:tok 日時:2008/02/25 10:49

return (STest**)(&Test); でエラーは出なくなりますが、確実にその戻り値を使うと問題が発生すると思います。 ローカル変数から返したい場合は、 STest* Test; Test = (STest*)malloc(sizeof(STest)*2*2); として、ポインタとしてTestを宣言してreturn Test;としてやればいいと思います。
Re: 多次元配列の構造体のポインタを返す方法 ( No.2 )
名前: 日時:2008/02/25 17:15

>Test = (STest*)malloc(sizeof(STest)*2*2); これは多次元配列ではなく1次元配列です。 Testは単純にSTest[4]と同じ連続領域が確保されます。 #N次元配列は連続したメモリ配置上での差異は #ないと思いますが上記のような返却では、 #返却した先での使用方法としてTest[1][1]のような #アクセス方法が出来ない為。 C言語では関数が配列を返す事は出来ない為、 ポインタにしますが、多次元配列の場合、 型をしっかり考える必要があります。 STest Test[2][2]; という定義に基づくと Testの型はSTest[2][2]; &Testの型はSTest(*)[2][2] となります。 あゆしゃさんのHPでは動的に多次元配列を 作成する方法が載っています。 ttp://ayusya.hp.infoseek.co.jp/ProgramAlgorithm.html ただし、これらの配列は連続した領域ではないので 解放する場合やポインタ計算する場合などは注意が必要です。 固定的な2次元配列などは 以下のような方法でも可能です。 typedef struct test{ int hogehoge; }TEST; typedef TEST (*TEST2ARY)[2]; TEST2ARY alloc_test( void ) { TEST (*test2)[2]; test2 = (TEST(*)[2])malloc( sizeof(TEST[2]) * 2 ); return test2; } int main(void) { int i, j; TEST2ARY test2ary; test2ary = alloc_test(); for( i=0; i<2; i++ ){ for( j=0; j<2; j++ ){ test2ary[i][j].hogehoge = i; } } for( i=0; i<2; i++ ){ for( j=0; j<2; j++ ){ printf ( "test2ary[%d][%d].hoge = %d\n", i, j, test2ary[i][j].hogehoge ); } } free( test2ary ); return 0; }
Re: 多次元配列の構造体のポインタを返す方法 ( No.3 )
名前:tok 日時:2008/02/29 16:28

訂正の方、ありがとうございました。 正確な意味での多次元配列の扱い方は知らなかったので、勉強になりました。 ついで、お手数でなければ知識深めるため、以下のコードに問題はないかお教えください。 #include <stdio.h> #include <stdlib.h> typedef struct{ int a; char b; } STest; STest* Return() { STest (*Test)[2] = (STest(*)[2])malloc(sizeof(STest[2]) * 2); Test[0][0].a = 10; Test[1][1].b = 11; return (STest*)Test; } int main() { STest (*test)[2] = (STest(*)[2])Return(); printf("%d, %d\n", test[0][0].a, test[1][1].b); free(test); return 0; } 主に心配なのは、STest*にキャストした時点でアドレスがずれたりする 危険性はないかどうかに関して、です。 ウチの環境(.NET2003)では STest* hoge = (STest*)Test; printf("%p\n", Test); printf("%p\n", hoge); で検証しましたが、同じアドレスでした。 これが環境依存な結果であった場合、上のコードは不適切となりますよね。 Cの仕様的にどうなのかが知りたいです。(K&R〜C99) ご存知の範囲で構わないですので、よろしくお願いします。
Re: 多次元配列の構造体のポインタを返す方法 ( No.4 )
名前: 日時:2008/02/29 17:10

ポインタ自体のサイズはどんなオブジェクトの型の ポインタであっても同じ環境であれば一律です。 STest* Return() を void* Return() のように考えるとわかりやすいかもしれません。 キャストはコンパイラをだましているだけなので、 少し言い過ぎかもしれませんが、Cの仕様を無視 させているという認識のほうが良いかと。 一番安全なのは引数でとると良いかもしれません。 int Return( STest (**Test)[2] ) { if ( Test==NULL ){ return 1; } (*Test) = (STest(*)[2])malloc(sizeof(STest[2]) * 2); if ((*Test)==NULL){ return 2; } (*Test)[0][0].a = 10; (*Test)[1][1].b = 11; return 0; } int main() { int ret; STest (*test)[2]; ret = Return( &test ); if ( ret ){ return 1; } printf("%d, %d\n", test[0][0].a, test[1][1].b); free(test); return 0; } これなら何故失敗したかの詳細も返せますし。
Re: 多次元配列の構造体のポインタを返す方法 ( No.5 )
名前:tok 日時:2008/02/29 21:19

ありがとうございました。 ポインタの配列であれば問題がなさそうに感じたんですけど、 配列へのポインタというのはどうなんだろうと考えていました。 けどよく考えたら、結局ポインタはポインタなんですよね。 配列へのポインタかどうかという情報は、単にコンパイラが区別する ためにだけあって、其れは一意のアドレスを表現する変数に過ぎないという。 いただいたサンプルコードの方は、読んでなるほどと思いました。 とはいえ、実は僕も通りすがりさんの形に合わせてみただけで、自分で やるとしたら引数に取ると思いますし、freeも生でなく、 何かでwrapして使うと思います。 割り込みの質問に答えていただいてありがとうございました。 ついで、一連の情報が通りすがりさんのために役立つことをお祈りします。

Page: 1 |