0

このコードをオンラインで見つけましたhttp://www.cplusplus.com/forum/beginner/6644/#msg30551これは、C++関数から配列を返すはずです。メモリ割り当て、スタック、ヒープ、ポインタなどに関して、この関数がどのように動作するかを示す説明が必要です。

int *f(size_t s){
    int *ret=new int[s];
    for (size_t a=0;a<s;a++)
        ret[a]=a;
    return ret;
}
4

4 に答える 4

3

私。

int *ret=new int[s];

1.retスタックにメモリを割り当てます - これはintポインタです 2.ヒープ
にサイズのある連続したメモリを割り当てます 3.割り当てられたメモリの最初の要素を指すようにします (2. から)s * sizeof(int)
ret


Ⅱ.

for (size_t a=0;a<s;a++)
    ret[a]=a;
  1. スタックにメモリを割り当てますa
  2. I. で割り当てられたメモリをループし、各要素に値を割り当てます。
  3. for-ステートメントの終了後は、aアクセスできなくなります ( でのみ使用できますfor) 。

III.

return ret;

I. で作成され、II. で初期化された配列の最初の要素を指すポインタのコピーをret返します。

の後、returnret破棄」されます。


この関数の呼び出し元は、呼び出して、このメモリの割り当てを解除 (解放) することを忘れてはなりませんdelete[]

例えば:

int * my_array = f( 6 );
// do sth with my_array
delete[] my_array;
于 2013-03-21T10:23:19.757 に答える
1

int実際には、この関数はs の配列 (すなわち)を返しませんint[N]。返されるのはint( int *) へのポインターです。sこのポインターは、 型の要素の配列の最初の要素を指していることがわかりますint

メモリが次のように割り当てられていることに注意してくださいnew

int *ret = new int[s];

したがって、 がint指す sの配列には、ret動的なストレージ期間があります。とりわけ、これは次のことを意味します。

1) コンパイラは、各配列要素のデストラクタを自動的に呼び出しません。(この場合、要素は型であるため、これは問題ではありませんがint、代わりに、非自明なデストラクタを持つクラス型の要素の場所である可能性があります。)

2) コンパイラは、割り当てられたメモリを自動的に解放しません。

対照的に、次のコードを検討してください。

void g() {
    int p[10]; // allocates 10 integer in the stack
    // use p ...
}

g終了すると、コンパイラは前述の操作を実行します。これを機能させるには、配列のサイズ (この例では 10) をコンパイル時に設定する必要があります。new元のコードのように、コンパイル時に必要なサイズがわからない場合。

動的に割り当てられた配列の場合、配列が不要になったときに前述の 2 つの操作が確実に実行されるようにするのはプログラマの責任です。これを行うには、次を呼び出す必要がありますdelete[]

delete[] p; // where p is a `int*` with the same value as `ret`

実際には、例外がスローされる可能性があるため、これは見かけよりも困難です。たとえば、このコードを考えてみましょう

void foo() {
    int* p = f(10); // where f is in the question
    // ... use the array pointed by p
    a_function_that_might_throw();
    delete[] p;
}

が例外をスローした場合、実行は削除されa_function_that_might_throwた時点に到達しません。pこの場合、new(inside f) によって割り当てられたメモリは、プログラムが終了するまで解放されません (リークします)。

この問題を回避するには、生のポインター (例: int*) の代わりに、スマート ポインター (例:std::unique_ptrまたはstd::shared_ptr) を使用することをお勧めします。

最後に、デフォルトでは、によって割り当てられるnewメモリはヒープ メモリです。ただし、この動作は変更できます。

于 2013-03-21T11:25:14.623 に答える
0
int *ret=new int[s];

この行は、自動保存期間を持つint*呼び出しを定義します。new-expressionによって返されたポインタretで初期化します。このnew 式は、動的ストレージ期間を持つ s の配列を作成し、その配列の最初の要素へのポインターを返します。ret new int[s]s int

これで、2 つのオブジェクトができました。int*自動保存期間を持つものint[]と、動的保存期間を持つものです。

for (size_t a=0;a<s;a++)

これはfor声明です。for-init-statementsize_tは、呼び出されるオブジェクトを定義し、aそれを 0 に初期化します。条件a、 が より小さいかどうかをチェックしますs。最後のはインクリメントしますa。これはa、範囲内でループすることを意味します[0, s)

ret[a]=a;

aこれにより、 の値がのa番目の要素に割り当てられretます。つまりret[0]、 value 0ret[1]value1などになります。

自動保存期間があり、そのスコープ (ステートメント)aの終わりに達したため、オブジェクトは破棄されます。for

return ret;

これは の値を返しますがret、これは でしたint*。したがって、関数の戻り値はint*、動的に割り当てられた配列の最初の要素を指すことになります。

自動保存期間があり、そのスコープ (関数)retの終わりに達したため、オブジェクトは破棄されます。fこれは関数内の単なるポインターであることに注意してください。動的に割り当てられた配列はまだ存在し、返されたポインターはまだそれを指しています。

delete[]後で、返されたポインターを覚えておく必要があります。

于 2013-03-21T10:23:45.597 に答える
0
int *ret =  new int[s];

これは動的に (~ ヒープ上で)s整数の配列を割り当て、それへの (実際には、その最初の要素への) ポインターを に格納しますret

残りの機能は簡単だと思います。

そのため、関数は動的に割り当てられた配列へのポインターを返しています。安全ではありません。呼び出し元が戻り値を保存せず、後でそれdelete[]を呼び出すと、リークが発生します。

于 2013-03-21T10:24:58.403 に答える