2009-08-03 15 views
1

私は次のコードを持っていると言います。関数呼び出しが終了した後に配列の内容を保持する。 (C++)

double *return_array(void) { 
    double foo[2]; 
    foo[0] = 5; 
    foo[1] = 6; 
    cout << foo << endl; 
    cout << foo[0] << endl << foo[1] << endl; 
    return foo; 
} 

double *bar = return_array() 
cout << bar << endl; 
cout << bar[0] << endl << bar[1] << endl; 

今、barとfooは同じポインタですが、そこにあったものは完全に変更されています。どうすればこの問題を回避できますか?基本的には、関数から6または9の倍数を渡す必要があります。私は何をすべきか?

+0

以下の良い返信に加えて、固定数の値がある場合、構造体クラスを作成して代わりに返すことができます。値の用途に応じて、読み込み/処理がより簡単になる場合があります。代わりにg = foo [gravity]を使用してください:g = foo.gravity –

答えて

4

通常、関数にあなたの事前に割り当てられたメモリに渡します。私が使用

int barsize = 2; 
double *bar = new double[barsize]; 
fill_array(bar, barsize); 
cout << bar << endl; 
cout << bar[0] << endl << bar[1] << endl; 
delete [] bar; 

void fill_array(double *foo, int foosize) 
{ 
    if (foosize < 2) 
    return; 

    foo[0] = 5; 
    foo[1] = 6; 
    cout << foo << endl; 
    cout << foo[0] << endl << foo[1] << endl; 
} 

ルールは同じ場所にメモリを割り当て、削除、常に...です。

または、std :: vectorを使用してください。彼らは素敵です=)私はもはや配列を使用しません。

+0

しかし、関数が呼び出される前にどれだけ割り当てる必要があるか分かっている場合にのみ機能します。結果のサイズが変わる可能性がある場合は、事前に割り当てられた領域を渡すことはできません。 – Amber

+2

@Dav:そのため、多くのC関数には飛行前モードがあります。 NULLポインタを渡すと、必要なサイズが返されます。メモリを割り当てて、もう一度呼び出します。だから私たちはC++ std :: vectorが大好きです。同じ場所での割り当てと削除に関するルールは良いものです。 –

+0

ええええええええええええええええええええええええええええええええと – Kieveli

1

newキーワードを使用して、スタックではなくヒープ上にメモリを割り当てます。

その後
double *return_array(void) { 
    double * foo = new double [2]; 
    foo[0] = 5; 
    foo[1] = 6; 
    return foo; 
} 

、それがdeleteを使用して行うの際に最終的に持っているメモリを解放します関数を呼び出すコード:

double * foo = return_array(); 
// ... 
delete [] foo; 
+0

あなたは常にメモリを作成する同じ場所で削除する必要があります。これは、誤った使用のために道路下のメモリリークを引き起こします。 – Kieveli

+0

メモリを解放する補完的な関数を作成することで、上記の関数を使ってそのルールに従うことはできますが、合意しました。しかし、私は通常、あなたの答えでやったようにそれをやります。 –

+0

...またはあなたはauto_ptrを返すことができ、心配しないでください)= – Kieveli

1

newを使用して、スコープされていないメモリを機能に割り当てます。

完了したらメモリを忘れずにdelete[]をメモリに入れてください。

0

結果をヒープに割り当てるか、std :: vectorを使用することができます。

5

ベクターを使用します。

std::vector<double> return_array(void) { 
    std::vector<double> foo; 
    foo.push_back(5); 
    foo.push_back(6); 
    cout << foo[0] << endl << foo[1] << endl; 
    return foo; 
} 

これは良い方法である、あなたはベクトルのコピーを避ける:

void fillVector(std::vector<double>& vec) 
{ 
    vec.push_back(5); 
    vec.push_back(6); 
} 

int main() 
{ 
    std::vector<double> vec; 

    fillVector(vec); 
} 

、バー、fooがまだ同じ ポインタですが、そこに何でした が完全に変更されました。

fooは関数のスタックに割り当てられているため、関数が返ってくるとdeallocatdを取得します。だから、barは実際にはどこにも向いていません!

0

常に固定数の要素を返していて、TR1拡張(またはブースト)を使用したい場合は、vectorまたは配列ではなくstd::tr1::tupleとします。これは、テンプレートクラスですので、あなたはそれをtypedefをしたいと思う、の線に沿って:タプルあなたの機能のリターンを作成するために、引数の適切な数(およびタイプ)と

typedef std::tr1::tuple<double, double, double, double, double, double> six_tuple; 

使用make_tuple()、およびその内容にアクセステンプレート付きget<N>()関数で、例えば:

six_tuple foo = std::tr1::make_tuple(1.0, 2.0, 3.0, 4.0, 5.0, 6.0); 
std::cout << std::tr1::get<0>(foo) << std::endl; // prints '1.0' 

コンパイラはmake_tuple()に引数の数や種類にイントロスペクション、そしてあなたは、タプルの間違ったソートに割り当てるしようとしている場合は、エラーがスローされます。

私は自分でメモリを管理するのが好きですが、あなたの走行距離は異なる場合があります。

+0

泥になる。あなたがしようとしていることを理解しようとする次の開発者は、あなたの名前を呪いの単語のリストに追加します。 – Kieveli

+0

不明な点は何ですか?私は自由にテンプレートのパラメータを認めるが、それはtypedefのためだ。タプルはTR1の標準の一部であり、配列が持たないあらゆる種類のC++機能をサポートしています。比較演算子(平等、小なり、&c)、ストリーム演算子の引数などとして使用することができます。さらに、return_array()内の何かが例外をスローすると、タプル(作成されていた場合)はスタックが巻き戻されるときに自動的に破棄されます。あなたは新しいものを使って割り当てを受けることはありません。 std :: tr1 :: tupleがあなたを怖がらせるならば、私が言うことができるのはstd :: tr1 :: bindがあなたに叫び声を上げることです。 –

+0

私はC++の基礎を学ぶ人に質問されることができます。あなたの答えは、より熟練したプログラマーにはうまく受け入れられますが、この状況では過度のことです。しかし、詳細をありがとう。 – physicsmichael

関連する問題