復習 前回の関数のまとめ(1) プログラムはmain()関数の先頭から実行される 関数を呼び出す側の実引数の値が関数内の仮引数(変数)に コピーされる 関数内で求めた値はreturn文によって関数値として呼び出し側に戻される. #include <stdio.h> float menseki(float a, float b) { return (a * b / 2); } int main(void) float x, y, kekka; printf("底辺は?"); scanf(" %f ", &x); printf("高さは?"); scanf(" %f ", &y); kekka = menseki(x, y); printf("面積は%fです.\n", kekka); x,y:実引数 a, b: 仮引数 仮引数もローカル変数 →関数内でのみ有効 関数の定義 スタートポイント 関数の呼び出し
menseki()関数内のローカル変数aとb 復習 ローカル変数(1) #include <stdio.h> float menseki(float a, float b) { float s; s = a * b / 2; return s; } int main(void) float a, b, kekka; printf("底辺は?"); scanf(" %f ", &a); printf("高さは?"); scanf(" %f ", &b); kekka = menseki(); printf("面積は%fです.\n", kekka); menseki()関数 menseki()関数内のローカル変数aとb ローカル変数 同じ変数名a, bでも,関数が違うと,別の変数と見なされる ⇒赤色a,bと青色a,bは別の変数 main()関数 main()関数内のローカル変数aとb
引数としてvoidと書くと,引数が無いことを宣言 復習 void キーワード 返却値を持たない(関数値のない)関数の定義 void kansu(float a, float b) { .... return; } voidは返却値が無いことを宣言 何も返さないので,return 式 ; とは書かない. return文の省略も可能! 引数としてvoidと書くと,引数が無いことを宣言 int main(void) { int x; x = kansu(3, 4); printf("x=%d, %d", x, kansu(2,5)); } int func(void) { return 5; } int main(void) printf("値は%d", func()); void 宣言された関数の返却値を利用しようとするとエラー
x a 12 120 12 復習 引数の値渡し 関数呼び出し main()関数 mul10()関数 変数 引数のコピー 引数のコピーバック 引数を10倍する関数 引数の値渡し main()関数 mul10()関数 int main(void) { int x = 12; mul10(x); printf("x = %d", x); } void mul10(int a) { a = a * 10; return; } 原則 引数は関数からコピーバックされない.呼び出し側の変数(実引数)は変化しない.⇒値渡し(call by value) x = 12 関数呼び出し a 12 x main()関数 変数 mul10()関数 12 引数のコピー 120 引数のコピーバック 局所変数 ローカル変数 return文実行 例外 ポインタ引数,配列引数 ⇒参照渡し(call by reference)
復習 配列引数(参照渡し)を用いた関数 配列引数は参照渡しであるため,呼び出し側の配列の値が変化する! 配列を引数とした関数呼び出し n個のデータの値を10倍する関数 復習 配列引数(参照渡し)を用いた関数 配列引数:かっこ[ ]のみつける.要素数を空欄にした配列 →data[n]× data[0]× data× #include <stdio.h> void mul10(int data[], int n) { int i; for (i = 0; i < n; i++) { data[i] = data[i]*10; } } int main(void) int i, aa[30], s; // 配列aaに30個のデータを入力する for (i = 0; i < 30; i++) printf("%d番のデータ:", i); scanf("%d", &aa[i]); } mul10(aa,30); printf("データを全て10倍すると"); //データの表示(省略) 理由:コンパイラから見たら普通の変数に見えるので× 理由:配列全体でなく要素を指定しているので× データの個数(n個)を引数とする 理由:この関数を再利用することを想定.データの個数はいつも30個とは限らないので,ループ回数を30回に固定したくない 配列引数は参照渡しであるため,呼び出し側の配列の値が変化する! 関数内のローカル配列変数dataを変化すると,呼び出し側の配列aaも変化 配列を引数とした関数呼び出し 配列名のみ書く.([ ]は不要) 理由1: 配列全体を引数としているのでインデックス付けない 理由2: コンパイラはすでにaaが配列であることを知っている 有効なデータの個数は30個
配列引数(参照渡し)における実引数と仮引数 復習 配列引数(参照渡し)における実引数と仮引数 #include <stdio.h> void mul10(int data[], int n) { int i; for (i = 0; i < n; i++) { data[i] = data[i]*10; } } int main(void) int i, aa[30], s; // 配列aaに30個のデータを入力する for (i = 0; i < 30; i++) printf("%d番のデータ:", i); scanf("%d", &aa[i]); } mul10(aa,30); printf("データを全て10倍すると"); //データの表示(省略) data[0] data[1] data[2] data[29] 仮引数配列data aa[0] aa[1] aa[2] aa[29] 実引数配列aa 配列の実体 配列の別名
関数のデバッグ (1) (2) (3) (1) ステップオーバー 次の行を実行 (2) ステップイン 関数内部に入る [A] ツールバーでデバッグを始める手順 ツールボタンで右クリックして,デバッグを選ぶ デバッグツールバーからボタンを選ぶ ステップインは関数内部に入って1行づつ実行する (1) (2) (3) ステップアウトは関数内部から呼び出し元にもどる (1) ステップオーバー 次の行を実行 (2) ステップイン 関数内部に入る (3) ステップアウト 関数内部から出る (3) デバッグの中止 デバッグをやめる プログラムが長い場合に非常に便利 [B] メニューでデバッグを始める手順 デバッグメニューで,ステップオーバーを選ぶ [C] プログラムの実行を止めたい場所のソースプログラムをポイントして,「カーソル行の前まで実行」メニューを使う
プログラミング技術の発達 初期の時代 構造化プログラミング オブジェクト指向プログラミング 暗黒時代.モジュール化困難. 理解しやすいプログラム,再利用可能なプログラムが できなかった. 数値計算 シミュレーション 機械制御(ロボット) 科目名 基礎プログラミング 応用プログラミング実習 初期のFORTRAN,初期のBASIC,etc... 構造化プログラミング ループ制御,選択制御の整理. ローカル変数の導入 → モジュール化が容易. 理解しやすいプログラム,再利用しやすいプログラム ができるようになった. 現代のプログラミング技術 C言語,Pascal,etc... オブジェクト指向プログラミング 一度作成したモジュールの徹底した再利用が可能. プログラミングの考え方の整理 グラフィカルユーザーインターフェース(GUI) アプリケーション(アプリ) 人工知能 科目名 プログラミングプロジェクト演習 C++,Java,C#,Objective-C
オブジェクトを中心としたプログラムの考え方 オブジェクト指向 オブジェクトを中心としたプログラムの考え方 オブジェクト = 物,全ての事物・事象 オブジェクトの例 人間 人間を表わす要素 性別,名前,年齢,身長,・・・,etc. 機械 機械を表わす要素 名前,重さ,部品の数,値段 実験データ 実験データを表わす要素 データ値の個数,データの値
構造体 ー オブジェクト指向の第一歩 いくつかの変数をまとめて新しい変数型を作る 例えば 複素数型 実部と虚部のfloat型の2変数からできている 日付型 年,月,日を表すint型の3変数からできている 学生身体データ型 学籍番号(int型変数) 名前(文字列変数) 誕生日(日付型構造体) 身長(float型変数) 体重(float型変数)
同じ構造をした「引き出し」変数を構造体変数と呼ぶ 例えば,課題が 「A君の誕生日をa,B君の誕生日をbとし,どちらが早く生まれたか比べなさい・・・」 日付aや日付bを表す変数があると便利 ⇒実際には日付は複数の変数でできている 構造体変数 箱のイメージ 1999 year 12 month 普通の変数 (ここでは年・月・日) 5 day 構造体変数 (ここでは日付) year month day a 引き出しのイメージ 構造体変数aの中のyear プログラム中では a.year year month day b ピリオド 構造体変数bの中のyear プログラム中では b.year ピリオド 同じ構造をした「引き出し」変数を構造体変数と呼ぶ
a b 構造体のプログラム例(1) ー 日付型 キーワード struct 構造体内の変数をメンバ変数と呼ぶ 2 構造体のプログラム例(1) ー 日付型 キーワード struct 構造体内の変数をメンバ変数と呼ぶ #include <stdio.h> struct Date { int year; int month; int day; }; void main() Date a, b; a.year = 2015; a.month = 7; a.day = 1; b = a; b.day = 2; printf("初めの日付は%d年%d月%d日,", a.year, a.month, a.day); printf("次の日付は%d年%d月%d日\n", b.year, b.month, b.day); } Date型の構造体の定義 Dateは変数ではなく設計図 year month day a 2015 7 1 year month day b 代入 2015 7 2 1 Date型の構造体変数 aとbの宣言 a.year は構造体変数aのメンバ変数yearを意味する 構造体変数aをbに代入 b.day は構造体変数bのメンバ変数dayを意味する 初めの日付は2015年7月1日,次の日付は2015年7月2日
Date型構造体配列のインデックス15の要素に値を代入 構造体のプログラム例(2) struct Date { int year; int month; int day; }; void main() Date a = {1998, 6, 28}; Date b; b = {1998, 6, 29}; Date c[20]; c[15].year = 1998; c[15].month = 6; c[15].day = 28; printf("今日は%d年%d月%d日\n", c[15].year, c[15].month, c[15].day); } 構造体変数を宣言すると同時に初期化 同時ではないのでダメ エラー Date型構造体の配列の宣言 Date型構造体配列のインデックス15の要素に値を代入 ※この例では配列の添え字15には特に意味はない
構造体のプログラム例(4) #include <stdio.h> struct Date { int year; Student型構造体sを仮引数とする関数の定義 引き出しの内容(情報)を丸ごと引数として受け取るイメージ #include <stdio.h> struct Date { int year; int month; int day; }; struct Student int number; //学籍番号 char name[20]; //名前 float height; //身長 float weight; //体重 Date birthday; //誕生日 void printSt(Student s) { printf("%d番%s(%d年%d月%d日生)", s.number, s.name,s.birthday.year, s.birthday.month, s.birthday.day); return; } void main() { Student matsu = {1020, "matsushima", 163.5, 62.0, {1970, 2, 28}}; printSt(matsu); printf("\n"); 1020番matsushima(1970年2月28日生) Student型構造体の変数sの内容を画面表示 代入 (コピー) Student型構造体のメンバとして文字列を指定 注意! s.number ○ number × Student型構造体変数matsuを実引数とした関数呼び出し Student型構造体のメンバとしてDate型構造体変数を指定
printSt()関数の定義はこの例では省略しているが実際は必要 構造体のプログラム例(5) #include <stdio.h> struct Date { int year; int month; int day; }; struct Student int number; //学籍番号 char name[20]; //名前 float height; //身長 float weight; //体重 Date birthday; //誕生日 void printSt(Student s); void check(Student a) { printSt(a); if (a.weight + 110 > a.height) { printf("は太りすぎだ!\n"); } else { printf("はいい感じだ!\n"); } return; } void main() { Student matsu = {1020, "matsushima", 163.5, 62.0, {1970, 2, 28}}; check(matsu); 注意! a.weight ○ weight × 1020番matsushima(1970年2月28日生)は太りすぎだ! printSt()関数の定義はこの例では省略しているが実際は必要