- 締切済み
C++ 配列を返すには?
C++で配列を返すにはどのようにしたらよろしいのでしょうか。 いろんなことを一応やってみましたが先頭の配列しか受け取ることができません。 また、受け取り方もよく分かってないのでその辺もお願いします。
- みんなの回答 (8)
- 専門家の回答
みんなの回答
- 麻野 なぎ(@AsanoNagi)
- ベストアンサー率45% (763/1670)
もうひとつ まず、CやC++の世界では、 関数の引数として配列を渡すような 表記は、単に、ポインタを渡してい るだけなので、引数として指定した 場合には、受け渡しだけでは、要素 毎のコピーは発生しません。 たとえば、 http://www.kouno.jp/home/c_faq/c6.html#4 にある、「 なぜなら配列が渡された ときに、関数が実際に受け取るのはポ インター であるからである」 さて、それだけではなんなので、 単純にポインタを引数とせずに配列 を渡す形にした方がわかりやすい例 です。 関数の引数に配列表現を使うのは、 多次元(実際には配列の配列)を 使うときにわかりやすくなるという 効果があります。 たとえば int color[1024][768]; というような配列を渡したいとき、 ポインタとしてやりくりするより、 シンプルに void revers(int color[1024][768]); のように渡して、関数内で配列として 取り扱う方がわかりやすいと思います。 ただ、厳密に言えば、 ・Cには多次元配列はない (あるのは、配列の配列の……) ・関数の引数で書いた配列の 要素数は無視される というのがあって、一番内側の 数字は無視されます。 ですので、 void revers(int color[][768]); でも同じです。 ただし、 void revers(int color[][]); void revers(int color[1024][]); はエラーになります。 また、たとえ、 void revers(int color[1024][768]); と書いても、実際の配列の要素数は チェックされませんので、注意が必要 です。 多次元配列はないという意味は、実は int color[1024][768]; は、 ・int [768] という配列の型があって ・それが、[1024] 個ある配列 という意味になります。 ですから、 void revers(int color[][768]); の内側の [] は、配列の要素数なので 無視される(なくても良い) 外側の [678] は、int [768] という 型の一部なので、省略不可 ということになります。
- jacta
- ベストアンサー率26% (845/3158)
初心者とのことなので、理解できる可能性は低いですが... 結果を格納する配列を引数として渡す場合、一般的には強い例外安全保障ができなくなります。配列の要素のコピーコンストラクタが決して失敗しないか、決して失敗しないswapが用意されている場合だけ、強い例外安全保障が可能になります。その場合でも、正しく実装するには相応の知識が必要です。 具体的には、 void func(std::string array[10]) { std::string temp[10] = { ... }; for (int i = 0; i < 10; i++) array[i].swap(temp[i]); } のようにしなければなりません。 つまり、関数内部で一通りのコピーが必ず発生します。
- 麻野 なぎ(@AsanoNagi)
- ベストアンサー率45% (763/1670)
再度補足です。 引数で配列を受け渡しする方法がわかりに くいので。 関数の仮引数の形で、配列を指定する 表現方法があります。 void func(int a[]); のようにすれば、この引数は、int の 配列であることを明示できます。 具体的な処理としても void func(int a[]) { int x = a[10]; // 呼び出したり、 a[11] = x + 1; // 代入したり } できます。 このとき、引数を経由した操作は、 呼び出し側に反映されます(後述) また、配列のサイズは直接渡されま せんので、上記の場合、a[10] や、 a[11] が存在しなくてもコンパイラは 何も言いません。 (実行時に良くないことが起こるで しょう) この関数を呼び出すときには、配列名を 引数にできます。 main() { int x[100]; func(x); のように } ただ、この場合は、本当は、配列を 引き渡しているのではなく、配列の 先頭を指すポインタを渡しているだ けです。 ですので、 void func(int a[]); は、 void func(int *a); と同じだと考えて差し支えありません。 実際には、このように、アドレスを 渡しているので、関数側の操作が 呼び出し側に反映されてしまうわけで す。
- 麻野 なぎ(@AsanoNagi)
- ベストアンサー率45% (763/1670)
補足です。 ANSI 以降のCでは、「構造体を返す」のは、 値をコピーするので処理コストがかかるとい う以上の問題はありません。 処理スピードを問題にしなければ、返せる 値のサイズにも上限はありません。 「構造体を返す」場合は、単に、値のコピー が発生するだけですから、メモリをどう確保 するかは、処理系にお任せすれば良いことに なっています。 ただ、普通は、関数の返値として返すのでは なく、引数として渡すことが多いですね。 int a[100]; に対して、 void func(a[]) { ..... } という関数に、 func(a); と渡せば、関数内で、配列 a を操作できます。 あえて、(構造体経由で)配列を「返す」なら たとえば、 a.h ------- struct array_type { int a[1024]; }; array_type func(int v); ------- a.cpp ------ #include "a.h" array_type func(int v) { array_type wk; for (int i = 0; i < 1024: i++) wk.a[i] = v; return wk; } ------ b.cpp ------ #include "a.h" int main() { arrya_type value; value = func(3.14); // ここで、値のコピーが発生する // いろいろな処理 // value.a[i] などで、配列としては機能する // でも、本当は、構造体 } ------ これで、あえて、メモリを明示的に確保すること も、メモリリークを起こすこともなく、実行は できます。 ただ、後で読む人が、「なぜここで構造体?」 と悩むことにはなると思います。 C++では、(明示的に定義してあれば)コピー コンストラクタというのがあって、これが悪さを するとか、これがないために、「単なる値のコピー」 が発生するとか、そういう話題はありますが、 普通に構造体を返すのは、上述のような、大きな データのコピーという問題があるだけです。
- nda23
- ベストアンサー率54% (777/1415)
ネイティブコードはプリミティブな値(Max64ビット)しか返せません。 オブジェクト型を返す場合でも関数からの戻り値はポインタで、本体は 別のメモリ空間にあります。 そもそも、C言語では配列の次元、要素数の管理は利用者の責任で 行うことになっています。つまり、「配列の先頭だけ渡すから、あとは 勝手にやってくれ」なのです。故に、要素数を5個しか定義していない 配列に対し、インデックスが6でアクセスしてもエラーになりません。 個人的な意見ですが、C、C++で配列や構造体を戻り値の型にするのは プログラムの効率的な作り方から見れば、「やってはいけない」の 代表格みたいなものです。 先ず、次のことを考えてみてください。 ★呼び出されたメソッドが返す配列は何処に作られたものか? 自動変数であれば、メソッドから返った時に解放されてしまい、 内容は不定になります。また、メソッド内でアロケートしたもの であるなら、メモリを解放する責任は誰にあるのか? ★それでも、明示的にアロケートしているなら百歩譲って良しと しましょう。しかし、単に構造体なりを返すと、先に述べたように 戻り値を保存しておくメモリを確保する内部コードが生成される ことがあります。(実際にそうなるケースが多い) すると、ソースコード上では見えないメモリを消費しますし、誰も 解放しないので、繰り返し実行するとメモリストレスになります。 よって、配列や構造体を返す場合は呼び出し側が領域を確保して、 そのポインタを渡し、呼び出されたメソッドはそこに結果を記録 するべきだと思います。
- 麻野 なぎ(@AsanoNagi)
- ベストアンサー率45% (763/1670)
配列全体を直接返す方法はありません。 ただ、構造体は直接返すことができます。 これを応用すると、配列をメンバーにし た構造体を返すことで、実質的に配列を 返すという手もあります。 同じく、配列は直接代入できないのでが、 構造体は直接代入できるので、配列をメ ンバーとする構造体経由で、配列を代入 したりもできます。
- SAYKA
- ベストアンサー率34% (944/2776)
通常は ポインタを渡すしかないんじゃないのかな 古い考えなら呼び元で領域確保して処理側へ確保できたポインタを渡して終ったら確保された値を順に使う・・・ 今は色々やり方は有るだろうけど大きくは変ってない筈・・・
- jacta
- ベストアンサー率26% (845/3158)
配列を直接返す方法はありません。 お勧めなのは、 std::auto_ptr< std::vector<int> > func(); のように、vectorをauto_ptrにして返す方法です。 auto_ptrにしておかないとvector全体のコピーが発生するため、効率が低下するとともに、例外が送出するリスクも発生します。
補足
C++を学び始めて1ヶ月もたっていないのでよく分かりません。 やりたいことはa.cppとb.cppでbで作った配列をaで受け取れるようにしたいのですがどのようにしていいか分からず困っています。 よろしくお願いします。