cの変数に使用されているメモリがいつ解放されるかを調べようとしています。i
例として、次のコード スニペットで整数が解放されるのはいつですか?
int function()
{
int i = 1;
// do some things
return 0;
}
cの変数に使用されているメモリがいつ解放されるかを調べようとしています。i
例として、次のコード スニペットで整数が解放されるのはいつですか?
int function()
{
int i = 1;
// do some things
return 0;
}
C では、他のすべての言語と同様に、ここに示すようなレキシカル スコープの変数は、i
そのスコープ内でのみ有効です。 のスコープi
は、その宣言から関数の閉じ括弧までです。それらが解放される正確な時期はしばしば指定されませんが、実際の C 実装では、ローカル変数は呼び出しスタックに割り当てられ、関数が戻るとそのメモリが再利用されます。
次のようなものを検討してください
int function()
{
int i; // beginning of i's scope
{
int j; // beginning of j's scope
...
} // end of j's scope
{
int k; // beginning of k's scope
...
} // end of k's scope
return 0; // all locals of the function are deallocated by the time it is exited
} // end of i's scope
スコープは、変数が名前でいつアクセスできるかを決定し、ローカル ( auto
) 変数の場合、それらのコンテンツに有効にアクセスできる時期を決定します (たとえば、ローカル変数のアドレスへのポインターを設定する場合、変数のスコープ外でのポインターの参照解除は未定義です)。行動)。解放は多少異なる問題です...ほとんどの実装は、j または k のスコープの最後でそれらを「解放」するために何もしませんが、両方の変数に同じメモリを再利用する可能性があります。戻るときfunction
、ほとんどの実装は、スタックポインターの1つのデクリメントによって、リターンアドレスとともにすべてのローカルをスタックから「ポップ」し、実際にはそれらのメモリを「割り当て解除」します...メモリはまだスタック上にありますが、「割り当て」の準備ができました
あなたの質問の用語はやや混乱していることに注意してください...変数にはスコープがありますが、割り当てられ、割り当て解除されるのは変数ではなくメモリです。たとえば、それらが定数であるか、プログラムで使用されていない場合、一部の変数にはメモリが割り当てられていない場合があります。上記のように、ローカル変数のメモリのみが割り当てまたは解放されます...静的およびファイルスコープ変数のメモリは解放されず、プログラムがロードされたときにのみ割り当てられます。また、プログラムによって (malloc/realloc/calloc/strdup/free などの呼び出しを介して) 明示的に割り当ておよび解放される他のメモリ (ヒープ メモリ) があります。ただし、ヒープメモリは参照できますがポインター変数によって、ポインター変数自体のメモリは参照 (メモリ アドレス) だけで構成され、変数のスコープはローカルまたは静的/ファイルのいずれかになります。
範囲外になると解放されます。関数スコープがあるため、これは関数が戻るときに発生します。
i
スタックに割り当てられます。return を実行すると解放されます。
C では、自動変数はスコープに対してローカルです。
スコープは基本的に '{' '}' でマークされているため、{} ペアの内側にいるときはスコープの内側にいます。もちろん、スコープはネストできます。
これが、古い C 標準ではローカル変数をスコープの先頭で定義する必要があった理由です。これにより、C コンパイラの記述が容易になり (コンパイラは「{」、次にすべての変数、次にステートメントを参照する)、対処しなければならなかった変数。これは C99 で変更され (私が思うに?)、その後、ステートメント間の任意の場所で変数を定義できるようになりました。
もちろん、これは非常に役立ちます。
int foo()
{
int k = 0; /* inside the scope of foo() function */
for(; k < 10; k++) { /* don't need k = 0; here we set it to zero earlier */
int i = 1; /* initialize inside the scope of the for loop */
i = i * 2; /* do something with it */
printf ("k = %d, i = %d\n", k, i);
}
#if 0
printf ("i = %d\n", i); /* would cause an unknown identifier error
* because i would be out of scope, if you changed
* #if 0 to #if 1
*/
#endif
return 0;
}
int main()
{
foo();
foo();
return 0;
}
foo() のループの反復では常に i = 2 であることに注意してください。
static
さらに興味深いのは、キーワードが変数の永続性をどのように変更するかです。
int bar()
{
int k = 0; /* inside the scope of bar() function */
for(; k < 10; k++) { /* don't need k = 0; here we set it to zero earlier */
static int i = 1; /* initialize inside the scope of the for loop */
i = i * 2; /* do something with it */
printf ("k = %d, i = %d\n", k, i);
}
#if 0
printf ("i = %d\n", i); /* would cause an unknown identifier error
* because i would be out of scope, if you changed
* #if 0 to #if 1
*/
#endif
return 0;
}
int main()
{
foo();
foo();
return 0;
}
変更点と、静的変数の処理方法に注意してください。
キーワード static を int k = 0; の前に置くと、for ループはどうなるでしょうか。?
C マクロは非常に便利です。速度と全体的な単純さのために、関数ではなく複雑なローカル マクロを定義したい場合があります。プロジェクトで大きなビットマップを操作したかったのですが、関数を使用して「and」「or」「xor」操作を実行するのは少し面倒でした。ビットマップのサイズが固定されたので、いくつかのマクロを作成しました:
#define BMPOR(m1, m2) do { \
int j; \
for (j = 0; j < sizeof(bitmap_t); j++ ) \
((char *)(m1))[j] |= ((char *)(m2))[j]; \
} while (0)
do { } while(0) は、スコープ付きブロックを if/for/while などに問題なくアタッチできる楽しいトリックです。ブロックは 1 回だけ実行されます (ブロックの END で while がチェックされるため)。コンパイラが while(0) を検出すると、ループが削除されます。そしてもちろん、これにより最後にセミコロンを置くことができるので、IDE と (後で) セミコロンが何であるかについて混乱することはありません。
上記のマクロは、次のように使用されました。
int foo()
{
bitmap_t map_a = some_map(), map_b = some_other_map();
BITOR(map_a, map_b); /* or map_a and map_b and put the results in map_a */
}
ここで do {} while(0) は、ローカル変数 j を使用したローカル スコープ、for ループ、および必要なその他すべてを許可しました。
変数がスコープ外になると、変数の割り当てが解除されます。コードでは、ステートメントの実行i
後に変数の割り当てが解除されます。return 0
変数のスコープの詳細については、こちらをご覧ください