静的メモリ割り当てと動的メモリ割り当ての違いは何ですか?
例を挙げて説明してもらえますか?
割り当てには、静的、自動、動的の3つのタイプがあります。
静的割り当ては、プログラムの起動時に変数のメモリが割り当てられることを意味します。サイズは、プログラムの作成時に固定されます。グローバル変数、ファイルスコープ変数、および関数内で定義されたstatic
で修飾された変数に適用されます。
自動メモリ割り当ては、関数内で定義された(非静的)変数に対して発生し、通常はstack(ただし、 C標準では、スタックの使用は義務付けられていません)。これらを使用して追加のメモリを予約する必要はありませんが、一方で、このメモリの有効期間の制御も制限されています。例:関数内の自動変数は、関数が終了するまでしか存在しません。
void func() {
int i; /* `i` only exists during `func` */
}
動的メモリ割り当ては少し異なります。これらのメモリロケーションの正確なサイズと寿命を制御できるようになりました。解放しないと、メモリリークが発生し、ある時点でシステムがそれ以上メモリを割り当てることができないため、アプリケーションがクラッシュする可能性があります。
int* func() {
int* mem = malloc(1024);
return mem;
}
int* mem = func(); /* still accessible */
上の例では、関数が終了しても、割り当てられたメモリはまだ有効でアクセス可能です。メモリを使い終わったら、解放する必要があります。
free(mem);
これは標準的なインタビューの質問です。
calloc()
、malloc()
およびフレンドを使用して、実行時にメモリが割り当てられます。ヒープデータ構造とは関係ありませんが、「ヒープ」メモリとも呼ばれることがあります ref 。
int * a = malloc(sizeof(int));
ヒープメモリは、free()
が呼び出されるまで持続します。つまり、変数の有効期間を制御します。
これは一般に「スタック」メモリと呼ばれるもので、新しいスコープに入ると(通常、新しい関数が呼び出しスタックにプッシュされると)割り当てられます。スコープから移動すると、自動メモリアドレスの値は未定義になり、 それらにアクセスするエラー になります。
int a = 43;
スコープは必ずしも機能を意味するわけではないことに注意してください。スコープは関数内でネストでき、変数は宣言されたブロック内でのみスコープ内になります。また、このメモリが割り当てられる場所は指定されていないことに注意してください。 (saneシステムでは、スタック上にあるか、最適化のためのレジスターになります)
コンパイル時に割り当てられ、静的メモリ内の変数の有効期間は プログラムの有効期間 です。
Cでは、static
キーワードを使用して静的メモリを割り当てることができます。スコープはコンパイル単位のみです。
より興味深いものになります extern
キーワードが考慮される場合 。 extern
変数がdefinedの場合、コンパイラはそのメモリを割り当てます。 extern
変数がdeclaredの場合、コンパイラーは変数がdefined他の場所。 extern
変数の宣言/定義に失敗するとリンクの問題が発生し、static
変数の宣言/定義に失敗するとコンパイルの問題が発生します。
ファイルスコープでは、staticキーワードはオプションです(関数の外側):
int a = 32;
ただし、関数スコープ内ではありません(関数内):
static int a = 32;
技術的には、extern
とstatic
は、Cの2つの別個の変数クラスです。
extern int a; /* Declaration */
int a; /* Definition */
最後のメモリクラスは「レジスタ」変数です。予想どおり、レジスタ変数はCPUのレジスタに割り当てる必要がありますが、実際の決定はコンパイラに任されています。 address-ofを使用して、レジスタ変数を参照に変換することはできません。
register int meaning = 42;
printf("%p\n",&meaning); /* this is wrong and will fail at compile time. */
ほとんどの最新のコンパイラーは、どの変数をレジスターに入れるべきかを選ぶ際にあなたよりも賢いです:)
コンパイル時に静的メモリが割り当てられると言うのはやや混乱します。特に、コンパイルマシンとホストマシンが同じではないか、同じアーキテクチャ上にないことを考慮し始める場合です。
静的メモリの割り当ては、コンパイル時に割り当てられるではなく、コンパイラによって処理されると考える方が良いかもしれません。たとえば、コンパイラはコンパイル済みバイナリに大きなdata
セクションを作成し、プログラムがメモリにロードされると、プログラムのdata
セグメント内のアドレスが割り当てられたメモリの場所として使用されます。これには、大量の静的メモリを使用する場合、コンパイルされたバイナリが非常に大きくなるという著しい欠点があります。半ダース行未満のコードから生成された数ギガバイトのバイナリを書くことは可能です。もう1つのオプションは、プログラムが実行される前に他の方法でメモリを割り当てる初期化コードをコンパイラーが挿入することです。このコードは、ターゲットプラットフォームとOSによって異なります。実際には、最新のコンパイラはヒューリスティックを使用して、これらのオプションのどれを使用するかを決定します。 10k、1m、10m、100m、1G、または10Gの項目の大きな静的配列を割り当てる小さなCプログラムを作成することで、これを自分で試すことができます。多くのコンパイラーでは、バイナリー・サイズは配列のサイズに比例して増加し続け、特定のポイントを過ぎると、コンパイラーが別の割り振り戦略を使用すると再び縮小します。
静的メモリ割り当て:
動的メモリ割り当て:
静的メモリ割り当て:コンパイラは、宣言された変数に必要なメモリ空間を割り当てます。演算子のアドレスを使用することにより、予約アドレスが取得され、このアドレスがポインタ変数に割り当てられます。宣言された変数には静的メモリがあり、ポインタ値をポインタ変数に割り当てるこの方法は、静的メモリ割り当てと呼ばれます。メモリはコンパイル時に割り当てられます。
動的メモリ割り当て: malloc()やcalloc()などの関数を使用してメモリを動的に取得します。これらの関数を使用してメモリを動的に取得し、これらの関数によって返される値がポインタ変数に割り当てられている場合、このような割り当ては動的メモリ割り当てと呼ばれます。メモリは実行時に割り当てられます。
静的メモリ割り当てと動的メモリ割り当ての違い
メモリは、プログラムの実行が始まる前に割り当てられます(コンパイル中)。
プログラムの実行中にメモリが割り当てられます。
実行中にメモリ割り当てまたは割り当て解除アクションは実行されません。
メモリバインディングは、実行中に確立および破棄されます。
変数は永続的に割り当てられたままです。
プログラム単位がアクティブな場合にのみ割り当てられます。
スタックとヒープを使用して実装されます。
データセグメントを使用して実装。
変数にアクセスするにはポインターが必要です。
動的に割り当てられたポインターは不要です。
動的よりも実行速度が速い。
静的よりも実行が遅い。
より多くのメモリスペースが必要です。
必要なメモリ容量が少なくなります。
静的メモリ割り当てには、コンパイル時にプログラムを実行する前にメモリが割り当てられます。動的メモリ割り当ては、実行時のプログラムの実行中に割り当てられたメモリです。
静的メモリ割り当て。割り当てられたメモリはスタックになります。
int a[10];
動的メモリ割り当て。割り当てられたメモリはヒープになります。
int *a = malloc(sizeof(int) * 10);
cにはガベージコレクター(GC)がないため、後者はfree dである必要があります。
free(a);