サイトマップ / C言語講座>出入り口>総目次>目次:ポインタ>関数や変数のメモリ配置
[複数の値を返す関数]←このソース→[ポインタとメモリブロック]
コンパイルしてできあがったプログラムは、実行時にどのようにメモリに配置されるのでしょうか。関数や、様々な記憶クラスの変数がどのようなアドレスに配置されるか調べれば、それがわかります。デバッガを使っても知ることができます。
配置のされ方は、コンパイラやコンピュータによって一部違うものがありますが、下記にその一例を示します。8桁の16進数でアドレスを表していることからわかるように、この場合、32ビットポインタでアクセスしています。
関数や変数は下記に示す4つの領域のどこかに配置されます(注)。
アドレス | 領 域 の 名 前 |
FFFFFFFF | スタック(メモリの下位に向かって伸びる) |
ここにヒープ領域とスタックのすき間(未使用)あり | |
ヒープ領域(メモリの上位に向かってのびる) | |
データセグメント(大きさ固定) | |
00000000 | コードセグメント(大きさ固定) |
注:これ以外に、もし可能ならばレジスタに、不可能ならばスタックに割り付けられるレジスタ変数があります。書き込み読み込み速度が他の領域に割り付けられた変数より速いです。下記のように宣言します。
register int i;
コードセグメントはプログラム領域、あるいは、関数領域とも呼びます。コードセグメントには関数が配置されます。
データセグメントは静的記憶領域ともいいます。プログラムを実行中サイズが変わりません。静的変数や大域変数(グローバル変数)が配置されます。
ヒープ領域は動的記憶領域ともいい、プログラム実行時にサイズが変化します。標準ライブラリ関数malloc( )でメモリの割付が行われ、free( )の呼び出しで解放されます。この領域にとった変数には名前を付けることはできません。メモリの動的割付は、なかなか手強いものがあるので、この講座の最後の章で取り扱います。
スタックは後入れ先出し(LIFO :Last in First Out)方式で、メモリの管理が行われます。後で入れたものほど、先に取り出されます。ここには、局所変数(ローカル変数)や、関数の引数が配置されます。
スタックは高位のメモリアドレスから低位に向かって伸び、ヒープ領域は逆に、低位から高位に向かって伸びて行くことに、注意して下さい。スタックがどんどん伸びていき、ヒープと衝突、あるいは、ヒープがどんどん伸びていきスタックと衝突して、プログラムが暴走してしまうことはあり得ます。この場合プログラムは破壊されます。エラーも警告もなくコンパイルできるが、実行時に異常がでる時があります。その場合、この原因であれば、変数や関数のアドレスをデバッカで調べるとわかることがあります。
今回のソースプログラムでは、色々な記憶クラスの変数のアドレスを表示させます。関数についても、関数の名前はそのアドレスを表しているので、名前を使って表示させています。実行した結果表示されたアドレスと、記憶クラスの関係を良く見て下さい。なお、スタックより高位のアドレスにヒープ領域を取るコンパイラもあります。 */
#include <stdio.h> #include <stdlib.h> /* malloc( )で必要 */ int gl; static int st; void Func(int n); void main(void); void Func(int n) { int i; printf("引数 n のアドレス : %p\n", &n); /* スタック */ printf("ローカル変数 i のアドレス : %p\n", &i); /* スタック */ } void main(void) { int *p = malloc(100 * sizeof(int)); printf("main( ) のアドレス : %p\n", main); /* コードセグメント */ printf("Func( ) のアドレス : %p\n", Func); /* コードセグメント */ printf("静的変数 st のアドレス : %p\n", &st); /* データセグメント */ printf("グローバル変数 gl のアドレス : %p\n", &gl); /* データセグメント */ printf("動的割付された変数 p のアドレス : %p\n", p); /* ヒープ領域 */ Func(1); } |
[複数の値を返す関数]←このソース→[ポインタとメモリブロック]
/* (C) 2000- YFプロ. All Rights Reserved. */ 提供:C言語講座−それ自体コンパイルできる教材を使った講座です−