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して使うと思います。
割り込みの質問に答えていただいてありがとうございました。
ついで、一連の情報が通りすがりさんのために役立つことをお祈りします。
|