• 検索結果がありません。

情報処理 Ⅱ 2007 年 11 月 26 日 ( 月 )

N/A
N/A
Protected

Academic year: 2021

シェア "情報処理 Ⅱ 2007 年 11 月 26 日 ( 月 )"

Copied!
28
0
0

読み込み中.... (全文を見る)

全文

(1)

情報処理Ⅱ

(2)

2

本日学ぶこと

関数と変数

目的

 関数を自分で定義し,変数の利用方法・範囲を明示的に制限 することで,適切な機能分割(モジュール化,再利用)を図る. 

してはいけないこと

 main関数のみで100行以上のプログラム  グローバル変数を駆使するプログラム プログラムを 読みやすくする ⇒ 保守性保守性向上 入p.109

(3)

3

関数

(Function)

関数の分類

 自作関数: 自分で定義する.⇒ 本日のテーマ  ライブラリ関数: 出来合いのもの.printfなど. 

なぜ関数を定義するのか?

 処理を共通化(一般化)する  プログラムの見通しをよくする  main関数がないとプログラムは動かない 入pp.274-275 リp.346

(4)

4

関数定義の方法

構文

:

型名

型名

関数名

関数名

(

(

引数並び

引数並び

) {

) {

...}

...}

 型名は,関数の戻り値の型.値を返さないときは,voidと書く.  引数並びは,0個以上の「型名 変数名」をカンマで挟んだもの. 引数がないときは,何も書かないか,voidvoidと書く.

 例: double myatof(const char *str0) {double myatof(const char *str0) {……}}  例: void procedure(int x, int y) {void procedure(int x, int y) {……}}

一括の変数宣言と異なり, このintは省略できない.

(5)

5

void型

 

void

void

は「何もない」や「無効な値」を表す型名

  ×× void x;void x;   ○○ void *x;void *x; 

用途

 関数が引数や戻り値を持たないことを明示するとき •

• void exit(int status);void exit(int status); •

• void procedure(void);void procedure(void);

 任意のポインタ型を表現するとき

• void *p;void *p; •

• void *malloc(size_t size);void *malloc(size_t size);

プログラムを終了するライブ ラリ関数.通常,exit(0);exit(0); もしくは exit(1);exit(1); のいず れかで呼び出す. 入p.274 リp.349, p.300, p.498, p.501

(6)

6

関数の呼び出し

関数定義の例:

double f(double x)

double f(double x)

{return x+1;}

{return x+1;}

関数呼び出しの例:

b=f(a);

b=f(a);

 x を関数 f の仮引数仮引数(parameter), a を関数 f の実引数実引数(argument) という.これらを区別する必要のないときは,ともに引数引数という. • 仮引数には型名も書く.実引数には書かない.  x = a; の代入を行ってから,関数本文の処理に入る.関数 の処理が終われば,変数 x (のオブジェクト)は消滅する.  x = f(x); と書いてもよい.このとき,仮引数の x と,実 引数の x (あらかじめ定義しておく)は,別のオブジェクトであ る. 変数aの値を引数として, 関数fを呼び出し,その戻 り値を,変数bに代入する. 入pp.277-278 リpp.347-348

(7)

7

return

関数処理中に

return

return

;

;

があれば,そこで関数の処理

を終え,値を

戻り値

戻り値

(return value)とする.

 値の前後にカッコは不要.

 戻り値の型がvoidなら, return;return; と書ける.

 戻り値の型がvoid以外なら,必ずreturn 値;で処理を終え

るように書く.

(8)

8

引数の授受

Cの関数呼び出しでは必ず

値渡し

値渡し

(call by value)にな

る.

 値渡し: 実引数のコピーが仮引数に格納される.その後,仮コピー 引数の値を変更しても,実引数の値には影響しない.  

参照渡し

参照渡し

(call by reference)をしたければ,ポインタ

値を引数とすればよい.

 参照渡し: 仮引数の値を変更すれば,実引数の値もそれに変 わる.Cではこの意味での参照渡しをすることができないが,ポ インタ値を渡すことで,その参照先の値を変えることができる.参照先の値を変える • ポインタ値とは…配列変数の名前,または変数に「&」をつけ たもの 入p.277, p.285 リpp.347-348

(9)

9

二つの値を交換する関数

値渡し ⇒ 失敗

 引数は関数内の仮引数にコピーされる.  関数内の仮引数の中で,値を交換しても,関数の外のオブジェ クトは変更されない. 

参照渡し ⇒ 成功

 関数の仮引数は,指し示す先を持つ.  「*ポインタ変数 = 値」とすることで,ポインタ変数が指し示す (関数の外の)オブジェクトに値を代入する. swapint_bad.c, swapint.c

(10)

10

値渡しで失敗する理由

コード(抜粋)

 void swapint_bad(int x, int y) void swapint_bad(int x, int y)

{ { int tmp; int tmp; tmp = x; tmp = x; x = y; x = y; y = tmp; y = tmp; } }   int x = 1, y = int x = 1, y = --1;1; swapint_bad(x, y); swapint_bad(x, y); 関数swapint_badの中 y = -1 x = 1 関数mainの中 y = -1 x = 1 tmp tmp=1 x = -1 y = 1

(11)

11

参照渡しで成功する理由

コード(抜粋)

 void swapint_good(int *void swapint_good(int *pxpx, int *, int *pypy) )

{ { int tmp; int tmp; tmp = * tmp = *pxpx;; * *pxpx = *= *pypy;; * *pypy = tmp;= tmp; } }   int x = 1, y = int x = 1, y = --1;1; swapint_good(&x, &y); swapint_good(&x, &y); 関数swapint_goodの中 関数mainの中 y = -1 x = 1 tmp tmp=1 x = -1 y = 1 py px リp.356

(12)

12

main関数の型

main関数の(戻り値の)型は,int とする.

 void main とする本も多いが,規格上適切ではない. 

正常終了は

return 0;

return 0;

と書き,

異常終了は

return 1;

return 1;

と書くのが一般的.

main関数が返す値,およびexit関数の引数は,

終了ステータス

(exit status)と呼ばれる.

 Linuxなら,コマンド実行後,「echo $?」を実行することで その値を確認できる.  「コンパイルが成功したときに限り,ファイルを実行する」が 一つのコマンドで書ける リpp.359-362

(13)

13

関数定義の順番

呼び出す関数は,呼び出す前に(プログラムファイルの上の

ほうで)宣言されていなければならない.

宣言や定義がない場合は,

int

int

関数名

関数名

();

();

とみなして呼

び出しを試みる.

対策

 呼び出す順序に注意して関数を並べる.  関数プロトタイプを使用する.

(14)

14

関数プロトタイプ

(Function prototype)

構文

:

型名

型名

関数名

関数名

(

(

引数の型の並び

引数の型の並び

);

);

 「引数の型の並び」は,「引数(型と変数)の並び」でもよい.こ のとき変数名は無視される.  一般に,各関数の定義より前(上)に記述する.  例: int swapcase(intint swapcase(int **, int *);, int *); 

関数プロトタイプを用いることで,

 関数定義の順番を気にすることなくプログラムを記述できる.順番を気にすることなく  関数の入出力が明確になる. セミコロンを忘れずに 「関数原型」 ともいう 入pp.278-279 リpp.350-351

(15)

15

変数

(Variable)・識別子・オブジェクト

識別子

(Identifier): 変数名,関数名,型定義名など

の「名前」

識別子とオブジェクト

(Object)の違い

 識別子は,プログラムファイル(静的)で記述される「ラベル」  オブジェクトは,プログラム実行中(動的)に生成される「実体」  同一の識別子に対して複数のオブジェクトが生成されることも ある.  

宣言

宣言

により,変数ならそのオブジェクト,関数ならその実行

コードが,記憶域(メモリ)上に割り当てられるとき,

その宣言を特に

定義

定義

という.

 関数プロトタイプや,externを用いた変数や関数の宣言, 構造体などの独自型定義は,この意味で定義ではない. 入p.223 リp.37, pp.102-103

(16)

16

変数を宣言・定義する際の注意点

型は何か?

グローバルかローカルか?

autoかstaticかexternか?

リpp.104-106

(17)

17

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

各変数は,定義された位置によって,有効範囲

(scope)を

持つ.

 グローバル変数 • あらゆるブロックの外で定義された変数. • 有効範囲はファイル末尾まで.  ローカル変数 • ブロックの中で定義された変数. • 有効範囲はブロック終了まで.  グローバル - global - 大域的 - あらゆるブロックの外  ローカル - local - 局所的 - あるブロックの中 「ブロックの中」とは, { と }で 挟まれた領域のこと 入pp.280-281 リpp.111-114 関数の仮引数も ローカル変数

(18)

18

識別子の宣言に関するルール

グローバルに同一の識別子を複数宣言できない.

一つのブロック内に,同一の識別子を複数宣言できない.

関数はブロック内で定義できない.必ずグローバル区間での

定義となる.

 GCC(演習室のコンパイラ)では,関数の中に関数を定義できる が,使用しないこと! 

ブロック内に変数を定義するときは,それより外にある同一

の識別子と重複してもよい.

 ただし,外にある同一の識別子は参照できない.  モジュール化に関して有用なルール. リp.114, p.225

(19)

19

型の属性

記憶域クラス

 extern, static, auto, register 

型修飾子

 const, volatile

:

extern void function1(const char *);

extern void function1(const char *);

int x(void) {static int c=0; ...}

int x(void) {static int c=0; ...}

(20)

20 プログラムが複数のソースファイルで 構成されることがある.大規模プログ ラミングでは当たり前だが,本授業で は実例を出さない.

記憶域クラス(1)

 

auto

auto

: そのオブジェクトの生存期間は自動記憶域期間で

ある.

 積極的にautoを書くことはない.  

static

static

: そのオブジェクトの生存期間は静的記憶域期間

である.

 必要なときに使う.  

extern

extern

: 他の場所で宣言された識別子を使用する.

 分割コンパイルで不可欠.  externとstaticは,関数に 対しても指定できる. リp.107

(21)

21

記憶域クラス(2)

静的記憶域期間 (

static変数)

 staticを指定した変数と,グローバル変数が該当する.  プログラムの実行に先立ち,オブジェクトが生成され,初期値が設定 される.プログラム終了まで破棄されない.  初期値を指定しないオブジェクトには 0 が代入される.  初期値は,コンパイル時に計算可能な定数式でなければならない. 

自動記憶域期間 (

auto変数)

 autoを指定した変数,staticやexternの指定なくブロック内で定 義した変数と,関数の仮引数が該当する.  宣言文を実行するたびに,オブジェクトが生成され,初期値があれば 毎回初期化される.ブロックを終えると,破棄される.  初期値を指定しないオブジェクトの初期値は不定.  初期値は任意の計算式でよい. 入pp.226-227 リp.110, pp.115-120

(22)

22

有効範囲?記憶域クラス?

ここで問題

(小テストではありません)  グローバルなstatic変数は,定義《 できる ∥ できない 》.  グローバルなauto変数は,定義《 できる ∥ できない 》.  ローカルなstatic変数は,定義《 できる ∥ できない 》.  ローカルなauto変数は,定義《 できる ∥ できない 》. 

ローカルな

static変数の用途

 ブロック内で情報を保存しておき,あとでまた実行するときに利 用する.  動的に確保することなく,配列領域を戻り値とする.  auto変数では扱いきれない大容量オブジェクト(100万個の int配列など)を取り扱う. リpp.118-119

(23)

23

配列の

auto変数(1)

関数の中で配列変数を定義すれば,関数処理の中で確保さ

れ,関数処理が終わると破棄されるような配列が作られる.

void print_message(void) void print_message(void) { {

char message[] = "Wakayama";

char message[] = "Wakayama";

printf("%s

printf("%s¥¥n", message);n", message); }

}

message

関数print_messageの中

'W'

'a'

'k'

'a'

'y'

'a'

'm' 'a'

'¥0'

(24)

24

配列の

auto変数(2)

関数の仮引数に配列変数を書けば,その配列と型が適合す

るポインタ変数になる.

void

void print_message(charprint_message(char message[])message[]) {

{

printf("%s

printf("%s¥¥nn", message);", message); } }  要素数(多次元配列の場合は左端)は無視される. 要素数なし・初期化なし(不完全型)でもよい.

message

関数print_messageの中

'W'

'a'

'k'

'a'

'y'

'a'

'm' 'a'

'¥0'

宣言の形は不完全型 実体はポインタ変数

(25)

25

変数の有効範囲の補足

破棄されるまでは,ブロックの外からでも

(ポインタなどで間

接的に

)オブジェクトの参照や値の書き換えができる.

⇒ ポインタによる参照渡しが可能となる.

関数内の

auto変数に対応するオブジェクトは,関数処理が

行われるたびに生成される.

⇒ 再帰関数が構成できる.

'W'

'a'

'k'

'a'

'y'

'a'

'm' 'a'

'¥0'

message

何らかの関数の中

wakayama

message[0] = 'w'; message[0] = 'w'; としてよい リp.121

(26)

26

staticの補足

グローバル区間で,変数や関数の定義に

staticをつける

と,その識別子の有効範囲は,宣言時からそのファイル終了

までとなる(ファイル有効範囲).

staticをつけなければ,

他のファイルからも参照され得る.

ローカルな

static変数がある関数は,再入可能(リエントラ

ント,

reentrant)でない.

  再入可能再入可能であれば,同じ値の引数で関数を呼び出せば,関数 内の処理,そして戻り値が必ず同じになる.複数のプログラム ルーチン(再帰呼び出しを含めて)から,同時かつ非同期に呼 び出すことができる.  不純関数ともいう. リp.112, p.118

(27)

27

型修飾子

 

const

const

: 対象となるオブジェクトの値を変えることができな

い.参照は可能.

 

volatile

volatile

: 処理系が知らないうちに値を変える可能性が

ある.参照は可能.

constの使用例:

 char *strcpy(char *dest, const char *src);char *strcpy(char *dest, const char *src);

*dest は 関数内実行中 左辺値にできる *src は 関数内実行中 左辺値にできない dest, srcともに 関数内実行中 左辺値にできる リp.109, p.516

(28)

28

まとめ

関数を自分で定義することができる.関数を呼び出すとき,

引数は値渡しで授受される.ポインタ値を渡せば,参照渡し

となり,関数外のオブジェクトの値を変えることができる.

変数には,型とは別の属性として,記憶域クラスと型修飾子

を指定できる.

static変数とauto変数とでは,大きく挙動

が異なる.

「変数の定義」と「オブジェクトの生成」は別.

オブジェクトの生成・破棄のタイミングに注意する.

参照

関連したドキュメント

関係委員会のお力で次第に盛り上がりを見せ ているが,その時だけのお祭りで終わらせて

この数字は 2021 年末と比較すると約 40%の減少となっています。しかしひと月当たりの攻撃 件数を見てみると、 2022 年 1 月は 149 件であったのが 2022 年 3

MPの提出にあたり用いる別紙様式1については、本通知の適用から1年間は 経過措置期間として、 「医薬品リスク管理計画の策定について」 (平成 24 年4月

平成 26 年の方針策定から 10 年後となる令和6年度に、来遊個体群の個体数が現在の水

性別・子供の有無別の年代別週当たり勤務時間

2012年11月、再審査期間(新有効成分では 8 年)を 終了した薬剤については、日本医学会加盟の学会の

賞与は、一般に夏期一時金、年末一時金と言うように毎月

交付の日から90日(特別管 理産業廃棄物は60日)以内 に運搬・処分終了票の送付を 受けないときは30日以内に