メモリとセグメント

プログラムはメモリをセグメントよばれる領域に分割してデータを格納しています。

セグメントには、

○スタックセグメント
ローカル変数、引数が収める

○データセグメント
グローバル変数を収める

○テキストセグメント(コードセグメント)
プログラムのコード部分を収める

の三つの種類があります。

下のプログラムは三つのセグメントのアドレスの具体例を表示させるものです。



#include<stdio.h>

int A,B;

int main(void)
{
        int a,b;
        printf("###ローカル変数はスタックセグメント格納###\n");
        printf("a       = %p\n", &a);
        printf("b       = %p\n", &b);
        printf("###グローバル変数はデータセグメント格納###\n");
        printf("A       = %p\n", &A);
        printf("B       = %p\n", &B);
        printf("###関数はテキストセグメント(コードセグメントへ格納)###\n");
        printf("printf  = %p\n", printf);
        printf("main    = %p\n", main);
        return 0;
}

実行例

###ローカル変数はスタックセグメント格納###
a = 0xbf832c3c
b = 0xbf832c38
###グローバル変数はデータセグメント格納###
A = 0x804a020
B = 0x804a024
###関数はテキストセグメント(コードセグメントへ格納)###
printf  = 0x8048318
main    = 0x80483f4

スタックオーバーフローを出す


関数を呼び出す度に、メモリ上のスタック領域にはローカル変数とリターンアドレスが格納される。
下のプログラムは、関数functionの中で1000個の要素を持つ配列を確保した後、再度自らを呼び出してまた1000個の要素を持つ配列を確保する関数です。
無限に配列が作成されるためスタック領域は容量オーバーをおこしてしまします。このことを「スタックオーバーフロー」と呼びます。


#include<stdio.h>

void function()
{
        char str[1000];
        printf("%p\n", str);
        function();
}

int main(void)
{
        function();
        return 0;
}


実行例

0xbff405b4
0xbff401a4
0xbff3fd94
0xbff3f984
0xbff3f574
0xbff3f164
0xbff3ed54
0xbff3e944
0xbff3e534
0xbff3e124
0xbff3dd14
0xbff3d904

・・・・以下続く・・・・



グローバル変数とローカル変数


グローバル変数とローカル変数のメモリ領域の違い

グローバル変数(var1_global, var2_global)とローカル変数(var_local)を宣言して、各々の


#include<stdio.h>

int var_global;

void funcA(void)
{
        int var_local2;
        printf("var_local2  : %p\n\n", &var_local2);
        return;
}  


int main(void)
{
        int var_local1;
        printf("var_global : %p\n\n", &var_global);
        printf("var_local1  : %p\n\n", &var_local1);
        funcA();
        return 0;
}

実行結果

var_global : 0x804a01c

var_local1  : 0xbfc48efc

var_local2  : 0xbfc48ecc


ローカル変数とスタック


C言語において、ローカル変数はスタックと呼ばれるメモリの領域に記憶されるようです。
スタックといえば情報科学でよくでてくるLIFO(Last In First Out)の形式で要素の出入りが管理される処理形態ですね。

下の例では、main関数から呼び出されたfuncAの中でvar2=100が宣言しています。
funcBでは、初期化をせずにvar3を宣言しています。そのため、var2の内容がスタックから開放されずに、var3の内容になってしまいました。

#include<stdio.h>

void funcA(void)
{
        int var2=100;
        printf("var2 = %d in funcA\n\n",var2);
        return;
}
void funcB(void)
{
        int var3;
        printf("var3 = %d in funcB\n\n",var3);
        return;
}

int main(void)
{
        int var1=777;
        printf("var1 = %d in main function\n\n",var1);
        funcA();
        funcB();

        return 0;
}


実行結果

var1 = 777 in main function

var2 = 100 in funcA

var3 = 100 in funcB