Transcript プログラミング言語論5
プログラミング言語論
第五回
理工学部
情報システム工学科
新田直也
手続き
手続き:一連の処理を行う機能単位.
FORTRAN, Basic
Pascal
C, C++
Java
---------
サブルーチン
プロシージャ(手続き)
関数
メソッド
名前をつけることができ,その名前で何度でも呼び
出すことができる.
手続きの有効性
z = x * y を行うWhile プログラム
z = 0;
c = 0;
while (c < y) {
d = 0;
while (d < x) {
z++;
d++;
}
c++;
}
int plus(int z, int y) {
int d = 0;
while (d < y) {
z++;
d++;
}
return z;
}
main() {
int z = 0;
int c = 0;
while (c < y) {
z = plus(z, y);
c++;
}
}
手続きの定義と呼び出し
int plus(int z, int y) {
int d = 0;
while (d < y) {
z++;
d++;
}
return z;
}
関数plusの定義(関数宣言)
main() {
int z = 0;
int c = 0;
while (c < y) {
z = plus(z, y);
c++;
}
}
関数plusの呼出し
手続きの引数と戻り値
int plus(int z, int y) {
int d = 0;
while (d < y) {
z++;
d++;
}
return z;
}
main() {
int z = 0;
int c = 0;
while (c < y) {
z = plus(z, y);
c++;
}
}
仮引数:定義側の引数
戻り値
実引数:呼出し側の引数
手続きの型
int plus(int z, int y) {
int d = 0;
while (d < y) {
z++;
d++;
}
return z;
}
main() {
int z = 0;
int c = 0;
while (c < y) {
z = plus(z, y);
c++;
}
}
すべての関数は型を持つ.
関数定義と呼出し側で型が一致
してなければならない.
前方参照とプロトタイプ宣言
int plus(int z, int y) {
int d = 0;
while (d < y) {
z++;
d++;
}
return z;
}
後方参照
main() {
int z = 0;
int c = 0;
while (c < y) {
z = plus(z, y);
c++;
}
}
int plus(int, int);
プロトタイプ宣言
main() {
int z = 0;
int c = 0;
while (c < y) {
z = plus(z, y);
c++;
}
前方参照
}
int plus(int z, int y) {
int d = 0;
while (d < y) {
z++;
d++;
}
return z;
}
値を返さない手続き
値を返さない手続きは以下のように定義する.
C, C++, Javaの場合: 戻り値を void に.
VBの場合: サブルーチンプロシージャとして定義.
値を返さない手続きの呼出し.
void view(int a) {
printf(“%d\n”, a);
}
main() {
view(10);
}
式として扱われない.
(値を評価できない.)
再帰呼び出し(1)
(もちろん)関数の中で関数を呼出すことが可能.
main() {
printf(“%d\n”, max3(12, 15, 11));
}
int max3(int x, int y, int z) {
return max2(max2(x, y), z);
}
int max2(int x, int y) {
if (x >= y) return x; else return y;
}
再帰呼び出し(2)
関数の中で自分自身を呼び出すとどうなるか?
int factorial(int x) {
if (x == 1) {
return 1;
} else {
return x * factorial(x – 1);
}
}
記憶クラス
メモリ管理は古くて新しい問題
使えるメモリは有限.
メモリの使い方は実行速度にも影響.
さまざまな環境: 携帯電話,デジタル家電…
「忘れてもいいことはさっさと忘れる」が基本.
長く覚えておくための記憶領域: ヒープ領域
一時的に覚えておくための記憶領域: スタック領域
プログラムのメモリマップ
各プログラムに割り当てられるメモリの領域は以下
のようになっている.
0xffff番地
スタック領域
領域が増減する
1プログラムに
割り当てられる
領域
ヒープ領域
静的領域
書き換え不可能
プログラム領域
0x0000番地
各領域の説明
プログラム領域:
プログラムの実行コード(機械語)が格納される.
静的領域:
プログラムが持つ定数などが格納される.
char *a = “This is a string.”;
printf(“Hello World!!”);
ヒープ領域:
大域変数(後で説明)が格納される.
スタック領域:
自動変数(後で説明),関数の引数,戻り番地などが格納される.
自動変数
自動変数:
関数呼出し,ブロック開始時に生成される.
関数からの復帰,ブロック終了時に消滅する.
スタック領域上に確保される.
main () {
int i, j;
func();
}
mainの中でのみ使用可能
mainを抜けると消滅
func() {
int x, y;
}
funcの中でのみ使用可能
funcを抜けると消滅
静的変数
静的変数:
自動変数と同様,宣言した関数内でしか見れない.
関数からの復帰時に消滅せず値が保持される.
ヒープ領域に確保される.
main () {
int i, j;
tick();
tick();
}
静的変数であることを示す記憶指定子
tick() {
static int count = 0;
count++;
}
funcの中でのみ使用可能
次回呼出し時に値が残っている
大域変数
大域変数(外部変数):
関数の外で宣言する.
複数の関数で値を共有できる.
プログラム実行中消滅しない.
ヒープ領域に確保される.
int i, j;
mainでもfuncでも使用可能
消滅しない
main () {
i = 1; j = 2;
func();
}
func() {
printf(“[%d,%d]”, i, j);
}
[1,2]が表示される
変数のスコープと寿命
スコープ: その変数を見れる範囲
寿命: その変数に値が保持されている期間
スコープ
寿命
自動変数
関数内
関数呼出しの間
静的変数
関数内
プログラムの全実行
大域変数
プログラム全体
プログラムの全実行
スコープと可視性
別々のスコープで同じ名前を使用できる.
名前が衝突したときは,内側のスコープを優先.
int i, j;
main内における i ,j
main () {
func1();
func2();
}
func1() {
int i, j;
}
func1内における i ,j
func2() {
int i, j;
}
func2内における i ,j
スタック領域の詳細
関数呼出しに応じて
スタック領域が確保される.
main () {
int x = 1;
x = input(x);
}
int input(int y) {
char s[10];
scanf(“%s”, s);
printf("%s\n", s);
return y + 1;
}
0xffff番地
main用
x
:
y
戻り番地
:
s[1]
s[0]
引数用
20バイト
input用
自動変数用
28バイト
0x0000番地
バッファオーバーフロー攻撃
scanfなどで戻り番地を上書きする.
戻り番地は29~32文字目
main () {
int x = 1;
x = input(x);
}
int input(int y) {
char s[10];
scanf(“%s”, s);
printf("%s\n", s);
return y + 1;
}
0xffff番地
main用
x
:
y
戻り番地
:
不正な
s[1]
コード
s[0]
引数用
20バイト
input用
自動変数用
28バイト
0x0000番地