Lecture MemoryAllocation final - Keio University...1 プログラミング第3同演習 補足資料...

16
1 プログラミング第3同演習 補足資料 メモリ空間 ` メモリ(記憶領域)は8bit(1byte) 毎にアドレス(番地)が割り当て られる ` 32bitOSの場合,アドレスは 0x00000000~0xffffffffまで ` あるアドレスを基準としたと 0xffffffff (上位) ` あるアドレスを基準としたと きに,そのアドレスより 0x00000000側を「下位アドレス」 0xffffffff側を「上位アドレス」 と呼ぶ ` プログラムはコード,データとも に,メモリ上に「ロード」される 0x00000000 0x00000001 0x00000002 8bit 0110 0001 (=‘a’) 0110 0010 (=‘b’) (下位) プログラムで使用するメモリの種類 ` コード ` 実行する命令 : s = 0; for ( ; n > 0; n = n - 1 ) { s = s + n; } ` データ ` 命令によって扱われるデータ } : int x, y; char a[10]; char *p; プログラムのメモリ割り当て(コード) ` コンパイラによって,アセンブリ言語に変換され,さらに アセンブラによってマシン語に変換される. : s = 0; for ( ; n > 0; n = n - 1 ) { s = s + n; } : C言語のプログラム : : move $s0, $zero L: beq $zero, $s1, Exit nop add $s0, $s0, $s1 addi $s1, $s1, -1 j L Exit: : : 00 00 10 21 10 20 00 04 00 00 00 00 00 43 10 21 08 00 00 01 24 21 ff ff : : アセンブリ言語 マシン語 コンパイラ % gcc ex8-1.c アセンブラはgccによって 自動的に呼び出される プログラムのメモリ割り当て(コード) ` マシン語がメモリにロード される : s = 0; for ( ; n > 0; n = n - 1 ) { s = s + n; } : 0010 0000 (0x20) 0000 0000 (0x00) 0000 0100 (0x04) (上位) : : 00 00 10 21 10 20 00 04 00 00 00 00 00 43 10 21 08 00 00 01 24 21 ff ff : : 0000 0000 (0x00) 0000 0000 (0x00) 1000 0000 (0x10) 0010 0001 (0x21) : ビッグエンディアンの場合 0001 0000 (0x10) (下位) プログラムのメモリ割り当て(データ) ` コンパイラによって,メモリ領域が確保される (もしくは,メモリ領域を確保するようなアセンブリ言語が プログラム中に自動的に埋め込まれる) int x, y; char a[10]; ・int型(32bit/4byte)を それぞれx,yという名前で1個づつ ・char型(8bit/1bye)を aという名前で10個 32bitOSの場合

Transcript of Lecture MemoryAllocation final - Keio University...1 プログラミング第3同演習 補足資料...

Page 1: Lecture MemoryAllocation final - Keio University...1 プログラミング第3同演習 補足資料 メモリ空間 `メモリ(記憶領域)は8bit(1byte) 毎にアドレス(番地)が割り当て

1

プログラミング第3同演習

補足資料

メモリ空間

メモリ(記憶領域)は8bit(1byte)毎にアドレス(番地)が割り当てられる

32bitOSの場合,アドレスは

0x00000000~0xffffffffまで

あるアドレスを基準としたと

0xffffffff

(上位)

あるアドレスを基準としたときに,そのアドレスより0x00000000側を「下位アドレス」0xffffffff側を「上位アドレス」と呼ぶ

プログラムはコード,データともに,メモリ上に「ロード」される

0x00000000

0x00000001

0x00000002

8bit

0110 0001 (=‘a’)0110 0010 (=‘b’)

(下位)

プログラムで使用するメモリの種類

コード

実行する命令

:

s = 0;

for ( ; n > 0; n = n - 1 ) {

s = s + n;

}

データ

命令によって扱われるデータ

}

:

int x, y;

char a[10];

char *p;

プログラムのメモリ割り当て(コード)

コンパイラによって,アセンブリ言語に変換され,さらにアセンブラによってマシン語に変換される.

:s = 0;for ( ; n > 0; n = n - 1 ) {

s = s + n;}

:

C言語のプログラム

:

:move $s0, $zero

L: beq $zero, $s1, Exitnopadd $s0, $s0, $s1addi $s1, $s1, -1j L

Exit::

:00 00 10 2110 20 00 0400 00 00 0000 43 10 2108 00 00 0124 21 ff ff

::

アセンブリ言語 マシン語

コンパイラ

% gcc ex8-1.c

※アセンブラはgccによって自動的に呼び出される

プログラムのメモリ割り当て(コード)

マシン語がメモリにロードされる

:s = 0;for ( ; n > 0; n = n - 1 ) {

s = s + n;}

:0010 0000 (0x20)

0000 0000 (0x00)

0000 0100 (0x04)

(上位)

:

:00 00 10 2110 20 00 0400 00 00 0000 43 10 2108 00 00 0124 21 ff ff

:

:

0000 0000 (0x00)0000 0000 (0x00)

1000 0000 (0x10)0010 0001 (0x21)

:

※ビッグエンディアンの場合

0001 0000 (0x10)

( )

(下位)

プログラムのメモリ割り当て(データ)

コンパイラによって,メモリ領域が確保される

(もしくは,メモリ領域を確保するようなアセンブリ言語がプログラム中に自動的に埋め込まれる)

int x, y;

char a[10];

・int型(32bit/4byte)をそれぞれx,yという名前で1個づつ

・char型(8bit/1bye)をaという名前で10個

※32bitOSの場合

Page 2: Lecture MemoryAllocation final - Keio University...1 プログラミング第3同演習 補足資料 メモリ空間 `メモリ(記憶領域)は8bit(1byte) 毎にアドレス(番地)が割り当て

2

プログラムのメモリ割り当て(データ)

(上位)

:

= a[0]でアクセス可能な1byte(8bit)のメモリ

= a[1]でアクセス可能な1byte(8bit)のメモリ

:

= a[2]でアクセス可能な1byte(8bit)のメモリ

:

(下位)

int x, y;

char a[10];

xという名前でアクセス可能な4byte(32bit)のメモリ

yという名前でアクセス可能な4byte(32bit)のメモリ

※32bitOSの場合

※32bitOSの場合

とすることで,コンパイラがメモリ上に割り当てた変数cのアドレスを得ることができる.

アドレスとポインタ

アドレス(&)

(上位)

:

?char c = ’a’;

0xaaaa1231

&c

#include <stdio h>

0xaaaa1232

0xaaaa1233

0xaaaa1234

:

0x61(’a’)

(下位)

cでアクセス可能な1byte(8bit)のメモリ

0xaaaa1230

0xaaaa122f

0xaaaa122e

0xaaaa122d

0xaaaa1231 #include <stdio.h>

main()

{

char c = ’a’;

printf(“%p¥n”,&c);

}

アドレスとポインタ

ポインタ(*)

char c = ’a’;char *p;p = &c;

0xaa

(上位)

:

0x12

0x2f

0xaaaa1231

0xaaaa1232

0xaaaa1233

0xaaaa1234

#include <stdio.h>

:

0xaa

0x61(’a’)

(下位)

0xaaaa122f

0xaaaa122e

0xaaaa122d

0xaaaa1231

cでアクセス可能な1byte(8bit)のメモリ

0xaaaa1230main()

{

char c = ’a’;

char *p = &c;

printf(“%p¥n”,&c);

printf(“%p¥n”,p);

}

pでアクセス可能な4byte(32bit)のメモリ

※ビッグエンディアンの場合※32bitOSの場合

アドレスとポインタ

ポインタ

: アドレスを表す

: アドレスの中身を表す

0xaa

(上位)

:

0x12

0x2f

0xaaaa1231

0xaaaa1232

0xaaaa1233

0xaaaa1234

#include <stdio.h>

p

*p

:

0xaa

0x61(’a’)

(下位)

0xaaaa122f

0xaaaa122e

0xaaaa122d

0xaaaa1231

0xaaaa1230main()

{

char c = ’a’;

char *p = &c;

printf(“%p¥n”,&c);

printf(“%p¥n”,p);

printf(“%c¥n”,*p);

}

※ビッグエンディアンの場合※32bitOSの場合

ポインタと配列

ポインタと配列(char型)

0xaa

0xaa

(上位)

:

0x12

0x29

0xaaaa1231

0xaaaa1230

0xaaaa1232

0xaaaa1233

0xaaaa1234 #include <stdio.h>

main()

{

char c[7] = ”hello!”;

char *p;

0x68(’h’)0x65(’e’)

0x6c(’l’)0x6c(’l’)

:

0x6f(’o’)

0x00(’¥0’)0xaaaa122f

0xaaaa122e

0xaaaa122d

0xaaaa1230

p = &c[0];

printf(”%p¥n”,c);

printf(”%p¥n”,p);

}0xaaaa122c

0xaaaa122b

0xaaaa122a

0x21(’!’)

0xaaaa1229cが表すアドレス

c[0]でアクセス可能な1byte(8bit)のメモリ

※ビッグエンディアンの場合※32bitOSの場合

ポインタと配列

ポインタと配列(char型)

0xaa

0xaa

(上位)

:

0x12

0x29

0xaaaa1231

0xaaaa1230

0xaaaa1232

0xaaaa1233

0xaaaa1234 #include <stdio.h>

main()

{

char c[7] = ”hello!”;

char *p;

0x68(’h’)0x65(’e’)

0x6c(’l’)0x6c(’l’)

:

0x6f(’o’)

0x00(’¥0’)0xaaaa122f

0xaaaa122e

0xaaaa122d

0xaaaa1230

for(p = &c[0]; *p !=’¥0’; p++){

putchar(*p);

}

}0xaaaa122c

0xaaaa122b

0xaaaa122a

0x21(’!’)

0xaaaa1229

※ビッグエンディアンの場合※32bitOSの場合

ループ1回目

Page 3: Lecture MemoryAllocation final - Keio University...1 プログラミング第3同演習 補足資料 メモリ空間 `メモリ(記憶領域)は8bit(1byte) 毎にアドレス(番地)が割り当て

3

ポインタと配列

ポインタと配列(char型)

0xaa

0xaa

(上位)

:

0x12

0x2a

0xaaaa1231

0xaaaa1230

0xaaaa1232

0xaaaa1233

0xaaaa1234 #include <stdio.h>

main()

{

char c[7] = ”hello!”;

char *p;

0x68(’h’)0x65(’e’)

0x6c(’l’)0x6c(’l’)

:

0x6f(’o’)

0x00(’¥0’)0xaaaa122f

0xaaaa122e

0xaaaa122d

0xaaaa1230

for(p = &c[0]; *p !=’¥0’; p++){

putchar(*p);

}

}0xaaaa122c

0xaaaa122b

0xaaaa122a

0x21(’!’)

0xaaaa1229

※ビッグエンディアンの場合※32bitOSの場合

ループ2回目

ポインタと配列

ポインタと配列(char型)

0xaa

0xaa

(上位)

:

0x12

0x2b

0xaaaa1231

0xaaaa1230

0xaaaa1232

0xaaaa1233

0xaaaa1234 #include <stdio.h>

main()

{

char c[7] = ”hello!”;

char *p;

0x68(’h’)0x65(’e’)

0x6c(’l’)0x6c(’l’)

:

0x6f(’o’)

0x00(’¥0’)0xaaaa122f

0xaaaa122e

0xaaaa122d

0xaaaa1230

for(p = &c[0]; *p !=’¥0’; p++){

putchar(*p);

}

}0xaaaa122c

0xaaaa122b

0xaaaa122a

0x21(’!’)

0xaaaa1229

※ビッグエンディアンの場合※32bitOSの場合

ループ3回目

ポインタと配列

ポインタと配列(char型)

0xaa

0xaa

(上位)

:

0x12

0x2c

0xaaaa1231

0xaaaa1230

0xaaaa1232

0xaaaa1233

0xaaaa1234 #include <stdio.h>

main()

{

char c[7] = ”hello!”;

char *p;

0x68(’h’)0x65(’e’)

0x6c(’l’)0x6c(’l’)

:

0x6f(’o’)

0x00(’¥0’)0xaaaa122f

0xaaaa122e

0xaaaa122d

0xaaaa1230

for(p = &c[0]; *p !=’¥0’; p++){

putchar(*p);

}

}0xaaaa122c

0xaaaa122b

0xaaaa122a

0x21(’!’)

0xaaaa1229

※ビッグエンディアンの場合※32bitOSの場合

ループ4回目

ポインタと配列

ポインタと配列(char型)

0xaa

0xaa

(上位)

:

0x12

0x2d

0xaaaa1231

0xaaaa1230

0xaaaa1232

0xaaaa1233

0xaaaa1234 #include <stdio.h>

main()

{

char c[7] = ”hello!”;

char *p;

0x68(’h’)0x65(’e’)

0x6c(’l’)0x6c(’l’)

:

0x6f(’o’)

0x00(’¥0’)0xaaaa122f

0xaaaa122e

0xaaaa122d

0xaaaa1230

for(p = &c[0]; *p !=’¥0’; p++){

putchar(*p);

}

}0xaaaa122c

0xaaaa122b

0xaaaa122a

0x21(’!’)

0xaaaa1229

※ビッグエンディアンの場合※32bitOSの場合

ループ5回目

ポインタと配列

ポインタと配列(char型)

0xaa

0xaa

(上位)

:

0x12

0x2e

0xaaaa1231

0xaaaa1230

0xaaaa1232

0xaaaa1233

0xaaaa1234 #include <stdio.h>

main()

{

char c[7] = ”hello!”;

char *p;

0x68(’h’)0x65(’e’)

0x6c(’l’)0x6c(’l’)

:

0x6f(’o’)

0x00(’¥0’)0xaaaa122f

0xaaaa122e

0xaaaa122d

0xaaaa1230

for(p = &c[0]; *p !=’¥0’; p++){

putchar(*p);

}

}0xaaaa122c

0xaaaa122b

0xaaaa122a

0x21(’!’)

0xaaaa1229

※ビッグエンディアンの場合※32bitOSの場合

ループ6回目

ポインタと配列

ポインタと配列(char型)

0xaa

0xaa

(上位)

:

0x12

0x2f

0xaaaa1231

0xaaaa1230

0xaaaa1232

0xaaaa1233

0xaaaa1234 #include <stdio.h>

main()

{

char c[7] = ”hello!”;

char *p;

0x68(’h’)0x65(’e’)

0x6c(’l’)0x6c(’l’)

:

0x6f(’o’)

0x00(’¥0’)0xaaaa122f

0xaaaa122e

0xaaaa122d

0xaaaa1230

※ビッグエンディアンの場合※32bitOSの場合

for(p = &c[0]; *p !=’¥0’; p++){

putchar(*p);

}

}0xaaaa122c

0xaaaa122b

0xaaaa122a

0x21(’!’)

0xaaaa1229

ループ7回目

Page 4: Lecture MemoryAllocation final - Keio University...1 プログラミング第3同演習 補足資料 メモリ空間 `メモリ(記憶領域)は8bit(1byte) 毎にアドレス(番地)が割り当て

4

ポインタと配列

ポインタと配列(int型)

0xaa

0xaa

0x02

0x12

0x18

0xaaaa1231

0xaaaa1230

0xaaaa1232

0xaaaa1233

0xaaaa1234

:

#include <stdio.h>

main()

{

int v[10];

int *p;

0x000x00

0x000x01

:

0x00

0x02

0xaaaa1224

0xaaaa1223

0xaaaa1222

※ビッグエンディアンの場合※32bitOSの場合

0xaaaa1221

0xaaaa1220

0xaaaa1219

0x00

0xaaaa1218

v[0] = 1;

v[1] = 2;

:

p = &v[0];

printf(”%d¥n”,*p);

p++;

printf(”%d¥n”,*p);

}

0x000xaaaa1224

コンパイラはポインタの「型」の大きさに応じて,ポインタに対する演算の方法を変更する

ポインタと配列

ポインタと配列(int型)

0xaa

0xaa

0x02

0x12

0x22

0xaaaa1231

0xaaaa1230

0xaaaa1232

0xaaaa1233

0xaaaa1234

:

#include <stdio.h>

main()

{

int v[10];

int *p;

0x000x00

0x000x01

:

0x00

0x02

0xaaaa1224

0xaaaa1223

0xaaaa1222

0xaaaa1221

0xaaaa1220

0xaaaa1219

0x00

0xaaaa1218

v[0] = 1;

v[1] = 2;

:

p = &v[0];

printf(”%d¥n”,*p);

p++;

printf(”%d¥n”,*p);

}

0x000xaaaa1224

※ビッグエンディアンの場合※32bitOSの場合

コンパイラはポインタの「型」の大きさに応じて,ポインタに対する演算の方法を変更する

関数へのポインタ

関数へのポインタ

#include <stdio.h>void func(){

printf(”hoge¥n”);}

main()0000 0100 (0 04)

(上位):

0x00

0x00

0x12

0x30

0xaaaa1231

0xaaaa1232

0xaaaa1233

0xaaaa1234

0xaaaa1230:

: main(){

void (*f)();

f = func;(*f)();printf(”%p¥n”,f);

}

0000 0000 (0x00)0000 0000 (0x00)

1000 0000 (0x10)0010 0001 (0x21)

:

0001 0000 (0x10)

0010 0000 (0x20)

0000 0000 (0x00)

0000 0100 (0x04)

(下位)0xaaaa1230

0xaaaa1231

0xaaaa1232

0xaaaa1233

0xaaaa1234

0xaaaa1235

0xaaaa1236

0xaaaa1237

fでアクセス可能な4byte(32bit)のメモリ

funcが表すアドレス

※ビッグエンディアンの場合※32bitOSの場合 funcの中身のマシン語が格納されているメモリ

関数へのポインタの配列

#include <stdio.h>

void func1(){

:}void func2(){

:}

f[0]f[1]f[2]

}void func3(){

:}

main(){

void (*f[3])();

f[0] = func1; f[1] = func2;f[2] = func3;for(i = 0; i < 3; i++){

(*f[i])();}

}

func1のコード

func2のコード

func3のコード

関数へのポインタの配列

#include <stdio.h>

void func1(){

:}void func2(){

:}

f[0]f[1]f[2]

}void func3(){

:}

main(){

void (*f[3])();

f[0] = func1; f[1] = func2;f[2] = func3;for(i = 0; i < 3; i++){

(*f[i])();}

}

func1のコード

func2のコード

func3のコード

関数へのポインタの配列

#include <stdio.h>

void func1(){

:}void func2(){

:}

f[0]f[1]f[2]

}void func3(){

:}

main(){

void (*f[3])();

f[0] = func1; f[1] = func2;f[2] = func3;for(i = 0; i < 3; i++){

(*f[i])();}

}

func1のコード

func2のコード

func3のコード

Page 5: Lecture MemoryAllocation final - Keio University...1 プログラミング第3同演習 補足資料 メモリ空間 `メモリ(記憶領域)は8bit(1byte) 毎にアドレス(番地)が割り当て

5

アドレスとポインタのまとめ

変数は’&’をつけると,そのアドレスを示す.

ポインタはアドレスを格納する特殊な変数.(ポインタの値を格納するためのメモリも割当てられる.)

ポインタは’*’をつけるとそのアドレスの内容を示す.

printf(”%p¥n”,&x);

ポインタは,その型に応じて演算の動作が異なる.(型に合わせた値が加減算される)

int x = 10;int *p = &x;printf(”%d¥n”,*p);

アドレスとポインタのまとめ

配列名や関数名は,その内容が存在するメモリのアドレスを示す.(メモリは割当てられない)

char x[10] = ”Hello!”;char *p = x;putchar(*p);

void func(){……

}

main(){void (*f)();f = func;(*f)();

}

アドレスとポインタのまとめ

配列の名前をポインタに代入 : OK

ポインタを配列の名前に代入 : NG

char x[10] = ”Hello!”;char *p;

p = x; // OK

x = p; // NG

p = &x[0]; // お勧め

メモリ領域の種類

メモリは大きく以下の4つの領域に分けられる

コード領域

コードを割り当てる領域

データ領域

静的に確保されるメモリを

0xffffffff(上位)

ヒープ領域

スタック領域

データ

静的に確保されるメモリを割り当てる領域

ヒープ領域

動的に確保されるメモリを割り当てる領域

スタック領域

一時的なデータを割り当てる領域0x00000000

(下位)

コード領域

ヒ プ領域

データ領域

コード

データ領域

「外部変数」,「static宣言した内部変数」が割当てられる領域

0xffffffff(上位)

ヒープ領域

スタック領域

int x;

int y = 10;

0x00000000(下位)

コード領域

ヒ プ領域

データ領域

y

char str[] = “abcdefg”;

int func(){

static int z;

static long count = 0;

:

}

スタック領域

「内部変数」が割当てられる

0xffffffff(上位)

ヒープ領域

スタック領域

int func(int x, char c){

int y;

float val[100];

0x00000000(下位)

コード領域

ヒ プ領域

データ領域

[ ]

:

return 0;

}

※関数の引数には,多くの場合はCPUのレジスタが用いられるが,引数の数が多くなった場合などはスタックが用いられる※内部変数にもCPUのレジスタが用いられる場合もある※関数の戻り値にはレジスタが用いられる.

Page 6: Lecture MemoryAllocation final - Keio University...1 プログラミング第3同演習 補足資料 メモリ空間 `メモリ(記憶領域)は8bit(1byte) 毎にアドレス(番地)が割り当て

6

スタックの動作

上位アドレスから下位アドレスに向って成長するメモリ領域

pushスタックに値を積む

:

0xfffffffe

0xffffffff

(上位)

?0xfffffffd

0xfffffffc

popスタックから値を取り出す

現在のスタックのアドレスはCPUのスタックポインタ(レジスタ)で表わされる.

(下位)

sp:0xfffffffc

CPU

※ビッグエンディアンの場合※32bitOSの場合

スタックの動作(push動作)

int型のデータ1つ(0x01234567とする)をpush

:

0xfffffffe

0xffffffff

(上位)

?0xfffffffd

0xfffffffc

CPU

(下位)

sp:0xfffffffc

CPU

※ビッグエンディアンの場合※32bitOSの場合

スタックの動作(push動作)

int型のデータ1つ(0x01234567とする)をpush

0xfffffffe

0xffffffff

(上位)

?0xfffffffd

0xfffffffc0x67

0x450xfffffffb

CPU0xfffffffa

:

(下位)

0x23

0x01 sp:0xfffffff8

CPU0xfffffffa

0xfffffff9

0xfffffff8

※ビッグエンディアンの場合※32bitOSの場合

スタックの動作(push動作)

int型のデータ(0x89abcdefとする)をもう一つpush

0xfffffffe

0xffffffff

(上位)

?0xfffffffd

0xfffffffc0x67

0x450xfffffffb

CPU0xfffffffa

(下位)

0x23

0x01 sp:0xfffffff4

CPU0xfffffffa

0xfffffff9

0xfffffff8

:

0xef

0xcd

0xab

0x89

0xfffffff7

0xfffffff6

0xfffffff5

0xfffffff4

※ビッグエンディアンの場合※32bitOSの場合

スタックの動作(pop動作)

int型のデータをpop→ 0x89abcdefが取り出される

0xfffffffe

0xffffffff

(上位)

?0xfffffffd

0xfffffffc0x67

0x450xfffffffb

CPU0xfffffffa

(下位)

0x23

0x01 sp:0xfffffff4

CPU0xfffffffa

0xfffffff9

0xfffffff8

0xfffffff7

0xfffffff6

0xfffffff5

0xfffffff4

?取り出された後のメモリの値は不定

:

※ビッグエンディアンの場合※32bitOSの場合

スタックの動作(pop動作)

もう一つint型のデータをpop→ 0x01234567が取り出される

0xfffffffe

0xffffffff

(上位)

?0xfffffffd

0xfffffffc?

?0xfffffffb

CPU0xfffffffa

取り出された後のメモリの値は不定

(下位)

? sp:0xfffffff4

CPU0xfffffffa

0xfffffff9

0xfffffff8

:

0xfffffff7

0xfffffff6

0xfffffff5

0xfffffff4

※ビッグエンディアンの場合※32bitOSの場合

Page 7: Lecture MemoryAllocation final - Keio University...1 プログラミング第3同演習 補足資料 メモリ空間 `メモリ(記憶領域)は8bit(1byte) 毎にアドレス(番地)が割り当て

7

内部変数のメモリ割り当て

もともとスタックポインタが0xbfc14e0cを示していたとする.

main(){

:1

sp:0xbfc14e0c

CPU

?0xbfc14e0a

0xbfc14e0b

(上位)

?0xbfc14e09

0xbfc14e08?

0xbfc14e07

?0xbfc14e0c

x = 1;func(x);:

}

void func(int x){

int y;:

y = 0x100;:

}(下位)

0xbfc14e07

0xbfc14e06

0xbfc14e05

0xbfc14e04

:

0xbfc14e03

0xbfc14e02

0xbfc14e01

0xbfc14e00

※ビッグエンディアンの場合※32bitOSの場合

内部変数のメモリ割り当て

関数の引数がスタックに積まれる

main(){

:1

0x000xbfc14e0a

0xbfc14e0b

(上位)

0x00

0x000xbfc14e09

0xbfc14e08?

0xbfc14e07 sp:0xbfc14e08

CPU

0x010xbfc14e0c

x = 1func(x);:

}

void func(int x){

int y;:

y = 0x100;:

}(下位)

0xbfc14e07

0xbfc14e06

0xbfc14e05

0xbfc14e04

:

0xbfc14e03

0xbfc14e02

0xbfc14e01

0xbfc14e00

※ビッグエンディアンの場合※32bitOSの場合

内部変数のメモリ割り当て

関数からのリターンアドレスがスタックに積まれる(例:0x12233445)

main(){

:1

0x000xbfc14e0a

0xbfc14e0b

(上位)

0x00

0x000xbfc14e09

0xbfc14e080x45

0xbfc14e07 sp:0xbfc14e04

CPU

0x010xbfc14e0c

x = 1func(x);:

}

void func(int x){

int y;:

y = 0x100;:

}(下位)

0x34

0x23

0x12

0xbfc14e07

0xbfc14e06

0xbfc14e05

0xbfc14e04

:

0xbfc14e03

0xbfc14e02

0xbfc14e01

0xbfc14e00

※ビッグエンディアンの場合※32bitOSの場合

内部変数のメモリ割り当て

内部変数がスタック上に割当てられる

main(){

:1

0x000xbfc14e0a

0xbfc14e0b

(上位)

0x00

0x000xbfc14e09

0xbfc14e080x45

0xbfc14e07 sp:0xbfc14e00

CPU

0x010xbfc14e0c

x = 1func(x);:

}

void func(int x){

int y;:

y = 0x100;:

}(下位)

0x34

0x23

0x12

0xbfc14e07

0xbfc14e06

0xbfc14e05

0xbfc14e04

:

0xbfc14e03

0xbfc14e02

0xbfc14e01

0xbfc14e00

※ビッグエンディアンの場合※32bitOSの場合

内部変数のメモリ割り当て

内部変数を使って演算が行われる.

main(){

:1

0x000xbfc14e0a

0xbfc14e0b

(上位)

0x00

0x000xbfc14e09

0xbfc14e080x45

0xbfc14e07 sp:0xbfc14e00

CPU

0x010xbfc14e0c

x = 1func(x);:

}

void func(int x){

int y;:

y = 0x100;:

}(下位)

0x34

0x23

0x12

0xbfc14e07

0xbfc14e06

0xbfc14e05

0xbfc14e04

:

0xbfc14e03

0xbfc14e02

0xbfc14e01

0xbfc14e00

0x00

0x01

0x00

0x00

※ビッグエンディアンの場合※32bitOSの場合

内部変数のメモリ割り当て

内部変数が破棄され,リターンアドレスに戻る.

main(){

:1

0x000xbfc14e0a

0xbfc14e0b

(上位)

0x00

0x000xbfc14e09

0xbfc14e080x45

0xbfc14e07 sp:0xbfc14e04

CPU

0x010xbfc14e0c

x = 1func(x);:

}

void func(int x){

int y;:

y = 0x100;:

}(下位)

0x34

0x23

0x12

0xbfc14e07

0xbfc14e06

0xbfc14e05

0xbfc14e04

:

0xbfc14e03

0xbfc14e02

0xbfc14e01

0xbfc14e00

※ビッグエンディアンの場合※32bitOSの場合

Page 8: Lecture MemoryAllocation final - Keio University...1 プログラミング第3同演習 補足資料 メモリ空間 `メモリ(記憶領域)は8bit(1byte) 毎にアドレス(番地)が割り当て

8

内部変数のメモリ割り当て

内部変数が破棄され,リターンアドレスに戻る.

main(){

:1

0x000xbfc14e0a

0xbfc14e0b

(上位)

0x00

0x000xbfc14e09

0xbfc14e08?

0xbfc14e07 sp:0xbfc14e08

CPU

0x010xbfc14e0c

x = 1func(x);:

}

void func(int x){

int y;:

y = 0x100;:

}(下位)

0xbfc14e07

0xbfc14e06

0xbfc14e05

0xbfc14e04

:

0xbfc14e03

0xbfc14e02

0xbfc14e01

0xbfc14e00

※ビッグエンディアンの場合※32bitOSの場合

内部変数のメモリ割り当て

スタックに積まれた関数への引数が破棄される.

main(){

:1

?0xbfc14e0a

0xbfc14e0b

(上位)

?0xbfc14e09

0xbfc14e08?

0xbfc14e07 sp:0xbfc14e0c

CPU

?0xbfc14e0c

x = 1func(x);:

}

void func(int x){

int y;:

y = 0x100;:

}(下位)

0xbfc14e07

0xbfc14e06

0xbfc14e05

0xbfc14e04

:

0xbfc14e03

0xbfc14e02

0xbfc14e01

0xbfc14e00

※ビッグエンディアンの場合※32bitOSの場合

値渡しと参照渡し

値渡しの場合

#include <stdio.h>

int add(int x, int y){

return x + y;}

ヒープ領域

(上位)

スタック領域

main(){

int x,y,z;x = 10;y = 20;

z = add(x,y);}

ヒ プ領域

(下位)

コード領域

データ領域

値渡しと参照渡し

値渡しの場合

#include <stdio.h>

int add(int x, int y){

return x + y;}

ヒープ領域

(上位)

スタック領域

x=?,y=?,z=?

main(){

int x,y,z;x = 10;y = 20;

z = add(x,y);}

ヒ プ領域

(下位)

コード領域

データ領域

値渡しと参照渡し

値渡しの場合

#include <stdio.h>

int add(int x, int y){

return x + y;}

ヒープ領域

(上位)

スタック領域

x=10,y=20,z=?

main(){

int x,y,z;x = 10;y = 20;

z = add(x,y);}

ヒ プ領域

(下位)

コード領域

データ領域

値渡しと参照渡し

値渡しの場合

#include <stdio.h>

int add(int x, int y){

return x + y;}

ヒープ領域

(上位)

スタック領域

x=10,y=20,z=?

10,20

main(){

int x,y,z;x = 10;y = 20;

z = add(x,y);}

ヒ プ領域

(下位)

コード領域

データ領域

引数の値がスタック上にコピーされる

(CPUのレジスタの場合もある)

Page 9: Lecture MemoryAllocation final - Keio University...1 プログラミング第3同演習 補足資料 メモリ空間 `メモリ(記憶領域)は8bit(1byte) 毎にアドレス(番地)が割り当て

9

値渡しと参照渡し

値渡しの場合

#include <stdio.h>

int add(int x, int y){

return x + y;}

ヒープ領域

(上位)

スタック領域

x=10,y=20,z=?

10,20

main(){

int x,y,z;x = 10;y = 20;

z = add(x,y);}

ヒ プ領域

(下位)

コード領域

データ領域リターンアドレスがスタックに積まれる

値渡しと参照渡し

値渡しの場合

#include <stdio.h>

int add(int x, int y){

return x + y;}

ヒープ領域

(上位)

スタック領域

x=10,y=20,z=?

10,20

引数を用いて演算が行われる

main(){

int x,y,z;x = 10;y = 20;

z = add(x,y);}

ヒ プ領域

(下位)

コード領域

データ領域

が行われる

値渡しと参照渡し

値渡しの場合

#include <stdio.h>

int add(int x, int y){

return x + y;}

ヒープ領域

(上位)

スタック領域

x=10,y=20,z=30

main(){

int x,y,z;x = 10;y = 20;

z = add(x,y);}

ヒ プ領域

(下位)

コード領域

データ領域

リータンアドレスに戻り,戻り値をzにコピーする

値渡しと参照渡し

参照渡しの場合

#include <stdio.h>

void add(int *x, int *y){

*x = *x + *y;}

ヒープ領域

(上位)

スタック領域

x=?,y=?

main(){

int x,y;x = 10;y = 20;

add(&x,&y);}

ヒ プ領域

(下位)

コード領域

データ領域

値渡しと参照渡し

参照渡しの場合

#include <stdio.h>

void add(int *x, int *y){

*x = *x + *y;}

ヒープ領域

(上位)

スタック領域

x=10,y=20

main(){

int x,y;x = 10;y = 20;

add(&x,&y);}

ヒ プ領域

(下位)

コード領域

データ領域

値渡しと参照渡し

参照渡しの場合

#include <stdio.h>

void add(int *x, int *y){

*x = *x + *y;}

ヒープ領域

(上位)

スタック領域

x=10,y=20

x,yのアドレス

main(){

int x,y;x = 10;y = 20;

add(&x,&y);}

ヒ プ領域

(下位)

コード領域

データ領域

引数の値がスタック上にコピーされるこの場合は,xとyのアドレスになる

Page 10: Lecture MemoryAllocation final - Keio University...1 プログラミング第3同演習 補足資料 メモリ空間 `メモリ(記憶領域)は8bit(1byte) 毎にアドレス(番地)が割り当て

10

値渡しと参照渡し

参照渡しの場合

#include <stdio.h>

void add(int *x, int *y){

*x = *x + *y;}

ヒープ領域

(上位)

スタック領域

x=10,y=20

x,yのアドレス

main(){

int x,y;x = 10;y = 20;

add(&x,&y);}

ヒ プ領域

(下位)

コード領域

データ領域リターンアドレスがスタックに積まれる

値渡しと参照渡し

参照渡しの場合

#include <stdio.h>

void add(int *x, int *y){

*x = *x + *y;}

ヒープ領域

(上位)

スタック領域

x=30,y=20

x,yのアドレス

引数を用いて演算が行main(){

int x,y;x = 10;y = 20;

add(&x,&y);}

ヒ プ領域

(下位)

コード領域

データ領域

引数を用いて演算が行われる

同時に,引数として与えられたポインタが指す内容も書き換えられる

値渡しと参照渡し

参照渡しの場合

#include <stdio.h>

void add(int *x, int *y){

*x = *x + *y;}

ヒープ領域

(上位)

スタック領域

x=30,y=20

main(){

int x,y;x = 10;y = 20;

add(&x,&y);}

ヒ プ領域

(下位)

コード領域

データ領域

リータンアドレスに戻る

関数の再帰呼び出しと内部変数/外部変数int num = 0;

main(){

:x = 15; y = 9;gcd = euclid(x, y);:

}

(上位)

ヒープ領域

スタック領域

int euclid(int x, int y){

num++;

if (y == 0) {return x;

} else if ((x % y) == 0){return y;

} else {return euclid(y, x % y);

}}

(下位)

コード領域

ヒ プ領域

データ領域

num = 0

関数の再帰呼び出しと内部変数/外部変数int num = 0;

main(){

:x = 15; y = 9;gcd = euclid(x, y);:

}

(上位)

ヒープ領域

スタック領域

x,y = 15, 9

int euclid(int x, int y){

num++;

if (y == 0) {return x;

} else if ((x % y) == 0){return y;

} else {return euclid(y, x % y);

}}

(下位)

コード領域

ヒ プ領域

データ領域

num = 0

1回目の呼び出し

関数の再帰呼び出しと内部変数/外部変数int num = 0;

main(){

:x = 15; y = 9;gcd = euclid(x, y);:

}

(上位)

ヒープ領域

スタック領域

x,y = 15, 9

int euclid(int x, int y){

num++;

if (y == 0) {return x;

} else if ((x % y) == 0){return y;

} else {return euclid(y, x % y);

}}

(下位)

コード領域

ヒ プ領域

データ領域

num = 1

1回目の呼び出し

Page 11: Lecture MemoryAllocation final - Keio University...1 プログラミング第3同演習 補足資料 メモリ空間 `メモリ(記憶領域)は8bit(1byte) 毎にアドレス(番地)が割り当て

11

関数の再帰呼び出しと内部変数/外部変数int num = 0;

main(){

:x = 15; y = 9;gcd = euclid(x, y);:

}

(上位)

ヒープ領域

スタック領域

x,y

y,x%y

= 15, 9= 9, 6

int euclid(int x, int y){

num++;

if (y == 0) {return x;

} else if ((x % y) == 0){return y;

} else {return euclid(y, x % y);

}}

(下位)

コード領域

ヒ プ領域

データ領域

num = 1

2回目の呼び出し

関数の再帰呼び出しと内部変数/外部変数int num = 0;

main(){

:x = 15; y = 9;gcd = euclid(x, y);:

}

(上位)

ヒープ領域

スタック領域

x,y

y,x%y

= 15, 9= 9, 6

int euclid(int x, int y){

num++;

if (y == 0) {return x;

} else if ((x % y) == 0){return y;

} else {return euclid(y, x % y);

}}

(下位)

コード領域

ヒ プ領域

データ領域

num = 2

2回目の呼び出し

ヒープ領域

関数の再帰呼び出しと内部変数/外部変数int num = 0;

main(){

:x = 15; y = 9;gcd = euclid(x, y);:

}

(上位)

スタック領域

x,y

y,x%y

y,x%y

= 15, 9= 9, 6= 6,3

ヒ プ領域

int euclid(int x, int y){

num++;

if (y == 0) {return x;

} else if ((x % y) == 0){return y;

} else {return euclid(y, x % y);

}}

(下位)

コード領域

データ領域

num = 2

3回目の呼び出しヒープ領域

関数の再帰呼び出しと内部変数/外部変数int num = 0;

main(){

:x = 15; y = 9;gcd = euclid(x, y);:

}

(上位)

スタック領域

x,y

y,x%y

y,x%y

= 15, 9= 9, 6= 6,3

ヒ プ領域

int euclid(int x, int y){

num++;

if (y == 0) {return x;

} else if ((x % y) == 0){return y;

} else {return euclid(y, x % y);

}}

(下位)

コード領域

データ領域

num = 3

3回目の呼び出し

ヒープ領域

関数の再帰呼び出しと内部変数/外部変数int num = 0;

main(){

:x = 15; y = 9;gcd = euclid(x, y);:

}

(上位)

スタック領域

x,y

y,x%y

y,x%y

= 15, 9= 9, 6= 6,3

ヒ プ領域

int euclid(int x, int y){

num++;

if (y == 0) {return x;

} else if ((x % y) == 0){return y;

} else {return euclid(y, x % y);

}}

(下位)

コード領域

データ領域

num = 3

3回目の呼び出し

戻り値:3

ヒープ領域

関数の再帰呼び出しと内部変数/外部変数int num = 0;

main(){

:x = 15; y = 9;gcd = euclid(x, y);:

}

(上位)

スタック領域

x,y

y,x%y

= 15, 9= 9, 6

ヒ プ領域

int euclid(int x, int y){

num++;

if (y == 0) {return x;

} else if ((x % y) == 0){return y;

} else {return euclid(y, x % y);

}}

(下位)

コード領域

データ領域

num = 3

2回目の呼び出し

戻り値:3

Page 12: Lecture MemoryAllocation final - Keio University...1 プログラミング第3同演習 補足資料 メモリ空間 `メモリ(記憶領域)は8bit(1byte) 毎にアドレス(番地)が割り当て

12

ヒープ領域

関数の再帰呼び出しと内部変数/外部変数int num = 0;

main(){

:x = 15; y = 9;gcd = euclid(x, y);:

}

(上位)

スタック領域

x,y = 15, 9

ヒ プ領域

int euclid(int x, int y){

num++;

if (y == 0) {return x;

} else if ((x % y) == 0){return y;

} else {return euclid(y, x % y);

}}

(下位)

コード領域

データ領域

num = 3

1回目の呼び出し

戻り値:3

ヒープ領域

関数の再帰呼び出しと内部変数/外部変数int num = 0;

main(){

:x = 15; y = 9;gcd = euclid(x, y);:

}

(上位)

スタック領域

戻り値:3

ヒ プ領域

int euclid(int x, int y){

num++;

if (y == 0) {return x;

} else if ((x % y) == 0){return y;

} else {return euclid(y, x % y);

}}

(下位)

コード領域

データ領域

num = 3

内部変数と関数の戻り値

main(){

:char *p = mystr();printf(“%s¥n”,p);

ヒープ領域

スタック領域

(上位)

CPUのスタックポインタ

:}

char *mystr(){

char a[10] = ”abcdefg”;return a;

}

ヒ プ領域

コード領域

データ領域

(下位)

内部変数と関数の戻り値

関数の呼び出し

main(){

:char *p = mystr();printf(“%s¥n”,p);

ヒープ領域

スタック領域

(上位)

リターンアドレスがスタックに積まれる

CPUのスタックポインタ

:}

char *mystr(){

char a[10] = ”abcdefg”;return a;

}

ヒ プ領域

コード領域

データ領域

(下位)

内部変数と関数の戻り値

関数の内部変数がスタック上に確保される

main(){

:char *p = mystr();printf(“%s¥n”,p);

ヒープ領域

スタック領域

(上位)

aという配列が取られ

abcdefg

CPUのスタックポインタ

:}

char *mystr(){

char a[10] = ”abcdefg”;return a;

}

ヒ プ領域

コード領域

データ領域

(下位)

aという配列が取られ,“abcdefg”に初期化される

内部変数と関数の戻り値

関数のリターン

main(){

:char *p = mystr();printf(“%s¥n”,p);

ヒープ領域

スタック領域

(上位)

関数がリターンし,pにaのアドレスが代入される

abcdefg

CPUのスタックポインタ

:}

char *mystr(){

char a[10] = ”abcdefg”;return a;

}

ヒ プ領域

コード領域

データ領域

(下位)

pが指すアドレス

Page 13: Lecture MemoryAllocation final - Keio University...1 プログラミング第3同演習 補足資料 メモリ空間 `メモリ(記憶領域)は8bit(1byte) 毎にアドレス(番地)が割り当て

13

内部変数と関数の戻り値

次の関数の呼び出し

main(){

:char *p = mystr();printf(“%s¥n”,p);

ヒープ領域

スタック領域

(上位)

関数の引数とリターンアドレスがスタックに積まれる

CPUのスタックポインタ

:}

char *mystr(){

char a[10] = ”abcdefg”;return a;

}

ヒ プ領域

コード領域

データ領域

(下位)

積まれる

pが指すアドレス

”abcdefg”の内容が上書きされてしまう

内部変数と関数の戻り値

ありがちなミス

// 文字列s1とs2を連結した結果を返す関数char *mystrcat(const char *s1, const char *s2){

char str[100];char *p = &str[0];

for(; *s1 != ’¥0’; s1++){for(; *s1 != ¥0 ; s1++){*p++ = *s1;

}for(; *s2 != ’¥0’; s2++){

*p++ = *s2;}*p = ’¥0’;

return &str[0];}

内部変数と関数の戻り値

対応その1 :呼び出し側で結果を格納する領域を用意しておく

main(){

char res[100];:mystrcat(&res[0], str1, str2);mystrcat(&res[0], str1, str2);:

}

void mystrcat(char *res, const char *s1, const char *s2){

for(; *s1 != ’¥0’; s1++){*res++ = *s1;

}for(; *s2 != ’¥0’; s2++){

*res++ = *s2;}*res = ’¥0’;

}

内部変数と関数の戻り値

対応その2 :static宣言された内部変数もしくは外部変数を使う

char *mystrcat(const char *s1, const char *s2){

static char str[100];char *p = &str[0];

スタック領域

for(; *s1 != ’¥0’; s1++){*p++ = *s1;

}for(; *s2 != ’¥0’; s2++){

*p++ = *s2;}*p = ’¥0’;

return &str[0];}

ヒープ領域

コード領域

データ領域

※但し,スレッドプログラミングなどで問題が発生する可能性がある.

内部変数と関数の戻り値

対応その2 :static宣言された内部変数もしくは外部変数を使う

char str[100];

char *mystrcat(const char *s1, const char *s2){

char *p = &str[0];

スタック領域

char *p = &str[0];

for(; *s1 != ’¥0’; s1++){*p++ = *s1;

}for(; *s2 != ’¥0’; s2++){

*p++ = *s2;}*p = ’¥0’;

return &str[0];}

ヒープ領域

コード領域

データ領域

※但し,スレッドプログラミングなどで問題が発生する可能性がある.

内部変数と関数の戻り値

対応その3 :ヒープにメモリ領域を確保する

char *mystrcat(const char *s1, const char *s2){

char *str, *p;

str = (char *)malloc(strlen(s1) + strlen(s2) + 1);

スタック領域

str (char )malloc(strlen(s1) strlen(s2) 1);

for(p = str; *s1 != ’¥0’; s1++){*p++ = *s1;

}for(; *s2 != ’¥0’; s2++){

*p++ = *s2;}*p = ’¥0’;

return str;}

ヒープ領域

コード領域

データ領域

Page 14: Lecture MemoryAllocation final - Keio University...1 プログラミング第3同演習 補足資料 メモリ空間 `メモリ(記憶領域)は8bit(1byte) 毎にアドレス(番地)が割り当て

14

ヒープ領域

動的にメモリが確保/破棄される領域

メモリの確保

0xffffffff(上位)

ヒープ領域

スタック領域

void *malloc(size_t size);

void *calloc(size_t nmemb, size_t size);

メモリの破棄

0x00000000(下位)

コード領域

データ領域

void free(void *ptr);

それぞれ,プロトタイプ宣言が”stdlib.h”に記述されているので,使用する時にはstdlib.hをインクルードする

ヒープ領域のメモリの確保

mallocの使い方0xffffffff

(上位)

ヒープ領域

スタック領域

#include <stdlib.h>

main(){

char *p;

void *malloc(size_t size);

0x00000000(下位)

コード領域

データ領域

int *q;:p = (char*)malloc(10);q = (int*)malloc(sizeof(int)*20);:free(p);free(q);

}

mallocが10byteの領域を空いているヒープ領域から確保してくれる

※ビッグエンディアンの場合※32bitOSの場合

ヒープ領域のメモリの確保

mallocの使い方0xffffffff

(上位)

ヒープ領域

スタック領域

#include <stdlib.h>

main(){

char *p;

mallocが4x20=80byteの領域を空いているヒープ領域から確保してくれる

void *malloc(size_t size);

0x00000000(下位)

コード領域

データ領域

int *q;:p = (char*)malloc(10);q = (int*)malloc(sizeof(int)*20);:free(p);free(q);

}

pが指すアドレス

※ビッグエンディアンの場合※32bitOSの場合

ヒープ領域のメモリの解放

freeの使い方0xffffffff

(上位)

ヒープ領域

スタック領域

#include <stdlib.h>

main(){

char *p;qが指すアドレス

void free(void *ptr);

0x00000000(下位)

コード領域

データ領域

int *q;:p = (char*)malloc(10);q = (int*)malloc(sizeof(int)*20);:free(p);free(q);

}

pが指すアドレス

※ビッグエンディアンの場合※32bitOSの場合

freeの引数になるアドレスは,malloc関数が返したものでなくてはいけない

ヒープ領域のメモリの解放

freeの使い方0xffffffff

(上位)

ヒープ領域

スタック領域

#include <stdlib.h>

main(){

char *p;qが指すアドレス

void free(void *ptr);

0x00000000(下位)

コード領域

データ領域

int *q;:p = (char*)malloc(10);q = (int*)malloc(sizeof(int)*20);:free(p);free(q);

}

※ビッグエンディアンの場合※32bitOSの場合

freeの引数になるアドレスは,malloc関数が返したものでなくてはいけない

ヒープ領域のメモリの解放

freeの使い方0xffffffff

(上位)

ヒープ領域

スタック領域

#include <stdlib.h>

main(){

char *p;

void free(void *ptr);

0x00000000(下位)

コード領域

データ領域

int *q;:p = (char*)malloc(10);q = (int*)malloc(sizeof(int)*20);:free(p);free(q);

}

※ビッグエンディアンの場合※32bitOSの場合

freeの引数になるアドレスは,malloc関数が返したものでなくてはいけない

Page 15: Lecture MemoryAllocation final - Keio University...1 プログラミング第3同演習 補足資料 メモリ空間 `メモリ(記憶領域)は8bit(1byte) 毎にアドレス(番地)が割り当て

15

ヒープを利用した例

main(){

char *p;:p = mystrcat(“test”,”hogehoge”);:free(p);

}

char *mystrcat(const char *s1 const char *s2)char *mystrcat(const char *s1, const char *s2){

char *str, *p;

str = (char *)malloc(strlen(s1) + strlen(s2) + 1);

for(p = str; *s1 != ’¥0’; s1++){*p++ = *s1;

}for(; *s2 != ’¥0’; s2++){

*p++ = *s2;}*p = ’¥0’;

return str;}

ヒープ領域メモリの割り当て/解放の注意

割り当てたメモリは必ず解放する必要がある

解放せず,確保し続けると「メモリリーク」が発生する

(なるべくmallocとfreeはセットで使用する.)

解放する時にfree関数に与えるアドレスは,必ずmalloc関数が返したものでなければならない

以下のようなコードはNGchar *p = (char*)malloc(10);

:for(; p != ’¥0’; p++){

*p = *str++;}free(p);

:

mallocとcallocの違い

引数には確保する「総バイト数」を指定する

ヒープ領域から「総バイト数分」のメモリを確保し,その先頭のアドレスを返す

void *malloc(size_t size);

id ll ( i t b i t i )

引数には,要素の個数(nmemb)と1つの要素のサイズ(size)を指定する

ヒープ領域から「(nmemb×size)バイト」のメモリを確保し,その先頭のアドレスを返す

確保されたメモリ領域は,「0」に初期化される

void *calloc(size_t nmemb, size_t size);

メモリ領域の種類のまとめ

メモリ領域には,大きく分けて以下の4つがあるコード : プログラムコードが配置される

データ : 外部変数,static宣言された内部変数が配置される

スタック : 内部変数が配置される

ヒープ : 動的に確保/破棄されるメモリ領域

関数の戻り値に内部変数へのポインタを用いてはいけない

ヒープ領域からメモリを確保/破棄する関数

malloc/callocとfreeはセットで使わなければならない

void *malloc(size_t size);

void *calloc(size_t nmemb, size_t size);

void free(void *ptr);

補足:バッファオーバーフローの手口

ヒープ領域

(上位)

スタック領域#include <stdlib.h>

main(){

char str[10];:gets(&str[0]);:

}ヒ プ領域

(下位)

コード領域

データ領域

}

は標準入力からEOFもしくは’¥0’が入力されるまでの文字列sで示される場所に格納する関数

char *gets(char *s);

補足:バッファオーバーフローの手口

ヒープ領域

(上位)

スタック領域#include <stdlib.h>

main(){

char str[10];:gets(&str[0]);:

}

main関数のリターンアドレス

ヒ プ領域

(下位)

コード領域

データ領域

}

は標準入力からEOFもしくは’¥0’が入力されるまでの文字列sで示される場所に格納する関数

char *gets(char *s);

Page 16: Lecture MemoryAllocation final - Keio University...1 プログラミング第3同演習 補足資料 メモリ空間 `メモリ(記憶領域)は8bit(1byte) 毎にアドレス(番地)が割り当て

16

補足:バッファオーバーフローの手口

ヒープ領域

(上位)

スタック領域#include <stdlib.h>

main(){

char str[10];:gets(&str[0]);:

}ヒ プ領域

(下位)

コード領域

データ領域

}

は標準入力からEOFもしくは’¥0’が入力されるまでの文字列sで示される場所に格納する関数

char *gets(char *s);

補足:バッファオーバーフローの手口

ヒープ領域

(上位)

スタック領域#include <stdlib.h>

main(){

char str[10];:gets(&str[0]);:

}ヒ プ領域

(下位)

コード領域

データ領域

}

は標準入力からEOFもしくは’¥0’が入力されるまでの文字列sで示される場所に格納する関数

char *gets(char *s);

10文字以上入力されると,main関数のリターンアドレスが上書きされる.リターンアドレスをスタック内に設定し,スタック内に悪意のあるコードを置くことで,main関数終了とともに,そのコードを実行させることが可能.