回答:
割り当てには、静的、自動、動的の3つのタイプがあります。
静的割り当てとは、プログラムの起動時に変数のメモリが割り当てられることを意味します。プログラムの作成時にサイズが固定されます。これは、グローバル変数、ファイルスコープ変数、およびstatic
定義済みの内部関数で修飾された変数に適用されます。
自動メモリ割り当ては、関数内で定義された(静的でない)変数に対して行われ、通常はスタックに格納されます(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;
スコープは必ずしも機能を意味するわけではないことに注意してください。スコープは関数内にネストでき、変数はそれが宣言されたブロック内でのみスコープ内になります。このメモリが割り当てられる場所が指定されていないことにも注意してください。(まともなシステムでは、スタック上、または最適化のために登録されます)
コンパイル時に割り当てられます*。静的メモリ内の変数の寿命はプログラムの寿命です。
Cでは、静的メモリはstatic
キーワードを使用して割り当てることができます。スコープはコンパイル単位のみです。
キーワードが検討されると、extern
物事はより面白くなります。extern
変数が定義されると、コンパイラはその変数にメモリを割り当てます。ときにextern
変数がされて宣言し、コンパイラは変数がされている必要が定義された他の場所。extern
変数の宣言/定義に失敗するとリンクの問題が発生し、static
変数の宣言/定義に失敗するとコンパイルの問題が発生します。
ファイルスコープでは、staticキーワードはオプションです(関数の外)。
int a = 32;
ただし、関数スコープ内ではありません(関数内):
static int a = 32;
技術的には、extern
およびstatic
Cの変数2つの別々のクラスであります
extern int a; /* Declaration */
int a; /* Definition */
特にコンパイルマシンとホストマシンが同じではない、または同じアーキテクチャ上にない可能性があることを検討し始めた場合、静的メモリがコンパイル時に割り当てられると言うのはやや混乱します。
静的メモリの割り当ては、コンパイル時に割り当てられるのではなく、コンパイラによって処理されると考える方が良い場合があります。
たとえば、コンパイラはdata
コンパイルされたバイナリに大きなセクションを作成し、プログラムがメモリに読み込まれると、data
プログラムのセグメントは、割り当てられたメモリの場所として使用されます。これには、多くの静的メモリを使用する場合、コンパイルされたバイナリを非常に大きくするという顕著な欠点があります。半ダース未満のコード行から生成されたマルチギガバイトのバイナリを書き込むことが可能です。別のオプションは、コンパイラーがプログラムを実行する前に他の方法でメモリーを割り当てる初期化コードを挿入することです。このコードは、ターゲットプラットフォームとOSによって異なります。実際には、最新のコンパイラーはヒューリスティックを使用して、これらのオプションのどれを使用するかを決定します。10k、1m、10m、100m、1G、10Gのいずれかのアイテムの大きな静的配列を割り当てる小さなCプログラムを作成することにより、これを自分で試すことができます。多くのコンパイラーでは、バイナリー・サイズは配列のサイズとともに直線的に増加し続け、特定のポイントを過ぎると、
最後のメモリクラスは「レジスタ」変数です。予想通り、レジスタ変数はCPUのレジスタに割り当てる必要がありますが、実際の決定はコンパイラに任されています。address-ofを使用してレジスタ変数を参照に変換することはできません。
register int meaning = 42;
printf("%p\n",&meaning); /* this is wrong and will fail at compile time. */
最近のほとんどのコンパイラーは、レジスターに入れる変数を選択するときに、あなたより賢いです:)
int * a = malloc(sizeof(*a));
のタイプが繰り返されないように、代わりに使用することをお勧めしa
ます。これにより、タイプのa
変更があったとしてもずっと簡単になります。
静的メモリ割り当て:コンパイラは、宣言された変数に必要なメモリ空間を割り当てます。演算子のアドレスを使用することにより、予約アドレスが取得され、このアドレスがポインタ変数に割り当てられる場合があります。宣言された変数のほとんどに静的メモリがあるため、これはポインタ値をポインタ変数に割り当てる方法は、静的メモリ割り当てと呼ばれます。メモリはコンパイル時に割り当てられます。
動的メモリ割り当て: malloc()やcalloc()などの関数を使用してメモリを動的に取得します。これらの関数を使用してメモリを動的に取得し、これらの関数によって返される値がポインタ変数に割り当てられている場合、そのような割り当ては動的メモリと呼ばれます実行中、allocation.memoryは暗殺されます。
静的メモリ割り当て:
動的メモリ割り当て:
静的メモリ割り当てと動的メモリ割り当ての違い
メモリは、プログラムの実行開始前(コンパイル時)に割り当てられます。
メモリはプログラムの実行中に割り当てられます。
実行中は、メモリの割り当てや割り当て解除のアクションは実行されません。
メモリバインディングは、実行中に確立および破棄されます。
変数は永続的に割り当てられたままです。
プログラム単位がアクティブな場合にのみ割り振られます。
スタックとヒープを使用して実装されます。
データセグメントを使用して実装されます。
変数にアクセスするにはポインターが必要です。
動的に割り当てられたポインタは必要ありません。
動的よりも実行が速い。
静的よりも実行が遅い。
より多くのメモリ容量が必要です。
必要なメモリ容量が少ない。