前回までの関数のまとめ 関数は main() 関数または他の関数から呼び出されて実行される. 関数を呼び出す側の実引数の値が関数内の仮引数 ( 変数 ) にコピーされる. 関数内で定義した変数は, 関数の外からは用いることができない ( ローカル変数 ). 一般に関数内で仮引数を変化しても, 呼び出し側の変数は変化しない ( 値渡し ). 関数内で求めた値は return 文によって関数値として呼び出し側に戻される. 呼び出し側では, 必要なければ戻り値を利用しなくてもかまわない. 戻り値が無い関数を定義する場合は void キーワードを用いる. #include <stdio.h> a,b 仮引数 float menseki(float a, float b) return (a b / 2); float x, y, kekka; printf(" 底辺は?"); scanf(" %f ", &x); printf(" 高さは?"); scanf(" %f ", &y); kekka = menseki(x, y); printf(" 面積は %fです. n", kekka); x,y 実引数 仮引数もローカル変数だ! 例外として参照渡しである配列引数, ポインタ引数を用いた場合は, 呼び出し側の変数を変化できる!
関数のプロトタイプ宣言 (1) #include <stdio.h> #include <stdio.h> float menseki(float a, float b) float s; s = a b / 2; return s; float kekka; kekka = menseki(3, 4); printf("s=%f n", kekka); float kekka; kekka = menseki(3, 4); printf("s=%f n", kekka); float menseki(float a, float b) float s; s = a b / 2; return s; ソースプログラム上で, 関数の定義は関数の呼び出しより先に書かれていなければならない 理由 : コンパイラはソースプログラムの先頭から順にソースプログラムを機械語に変換するため, 関数の定義より先に関数の呼び出しがあると機械語に変換できない.
関数のプロトタイプ宣言 (2) #include <stdio.h> #include <stdio.h> float func1(...) // 何かの関数 1... b = func2(...); return s; void func2(...) // 何かの関数 2... c = func1(...); return; void func2(...) // 何かの関数 2... c = func1(...); return; float func1(...) // 何かの関数 1... b = func2(...); return s;... x = func1(...); y = func2(...);... x = func1(...); y = func2(...); 関数がお互いに呼び出しあうソースプログラムは記述不可能??
関数のプロトタイプ宣言 (3) #include <stdio.h> float menseki(float a, float b); float kekka; kekka = menseki(3, 4); printf("s=%f n", kekka); 関数のプロトタイプ宣言 ソースプログラム上で, 関数の呼び出し前に, 関数の定義か, プロトタイプ宣言のどちらかが絶対必要 printf() 関数や scanf() 関数では不要? float menseki(float a, float b) float s; s = a b / 2; return s; No! 絶対必要 printf() や scanf() のプロトタイプ宣言は stdio.h ファイルに定義されている. プロトタイプ宣言 = 関数定義の 1 行目プロトタイプ宣言は関数の使用方法 ( 引数の数と型, 戻り値の型 ) を示している
ヘッダファイル 関数のプロトタイプ宣言を集めてあるファイル ヘッダファイル (xxxxx.h) ヘッダファイルをソースプログラム内に読み込む命令 #include #include <stdio.h> stdio.h という名前のヘッダファイルを読み込む これをライブラリ関数と呼ぶ stdio.h あらかじめ用意されている標準入出力関数であるprintf() やscanf() などのプロトタイプ宣言が書かれているヘッダファイル (standard input output) math.h sqrt() などの数値計算関数のヘッダファイル (mathematics)
実行プログラム ( 機械語プログラム ) ができるまで ヘッダファイル ( ライブラリ関数の使用法 ) の読み込みソースプログラム1 ソースライブラリプログラム2 ソース関数 1 プログラム3 ライブラリ関数 2 コンパイルライブラリ関数 3 リンク ライブラリ関数本体の結合 実行プログラム
実行プログラムができるまで ( もっと詳しく!) プロジェクト名 kadai12-1 ソースファイル名 source12-1.cpp ソースプログラム source12-1.cpp テキストファイル プリプロセッサ ヘッダファイルの読み込み等の処理 コンパイル プリプロセス ( 事前処理 ) されたソースプログラム (source12-1.i) テキストファイル コンパイラ 機械語への変換 注 : プリプロセスされたソースプログラムは一般にはファイルとして作成されない オブジェクトファイル source12-1.obj バイナリファイル リンク リンカ ライブラリとオブジェクトファイルの結合 実行プログラム kadai12-1.exe バイナリファイル コンパイル + リンク = ビルドと呼ぶことがある テキストファイル文書として読めるファイルバイナリファイル文書として読めないファイル ( 機械語 )
プリプロセッサ命令は # で始まる プリプロセッサ命令 #include < 標準ヘッダファイル名 > #include " 自作ヘッダファイル名 " #define マクロ名マクロ文字列 スペース ( 空白 ) またはタブ ヘッダファイルを読み込むマクロ名をマクロ文字列で置き換える ソースファイル :kadai12.cpp #include "rei12.h" #define teisu 35 #define moji 'B'+15 int x,y; x = teisu + 22 + moji; func1(x); y = func2(teisu, moji); 自作ヘッダファイル :rei12.h void func1(int a); float func2(int a, char b); プリプロセス プリプロセッサの処理後 void func1(int a); float func2(int a, float b); int x,y; x = 35 + 22 + 'B'+15; func1(x); y = func2(35, 'B'+15); コンパイル
標準ライブラリ関数の例 プロトタイプヘッダファイル説明 double sqrt(double x) math.h x の平方根を返す double pow(double x, double y) math.h x の y 乗を返す double cos(double x) math.h cos x を返す.x の単位はラジアン double sin(double x) math.h sin x を返す.x の単位はラジアン double tan(double x) math.h tan x を返す.x の単位はラジアン double atan(double x) math.h tan 1 x を返す. 返り値の単位はラジアン double log10(double x) math.h 常用対数 log 10 x を返す int rand(void) stdlib.h 0~RAND_MAX の間の疑似乱数を返す void srand(unsigned seed) stdlib.h 擬似乱数の発生系列を seed に変更する int strlen(char s[]) string.h 文字列 s の文字数を返す char _strset(char s[], int c) string.h 文字列 s をアスキーコード c の文字で埋める char strcpy(char s1[], char s2[]) string.h 文字列 s1 を文字列 s2 にコピーする char はポインタ.2 年生で学習 int strcmp(char s1[], char s2[]) string.h 文字列 s1 と文字列 s2 を比較する. 同じ文字列なら 0 を返す. 辞書の順序で s1 が s2 より前なら, 正の値を返す. s1 が s2 より後なら, 負の値を返す. RAND_MAXはマクロ名.stdlib.hで定義されている 注 ) プロトタイプの表記は, 現在の学習レベルに合わせて変更してある. これらの関数の本来のプロトタイプはこの表とは異なる場合がある.
標準ライブラリ関数を用いたプログラムの例 (1) #include <stdio.h> #include <math.h> #define PI 3.1415 double x; x=0 から 2 まで /10 毎に sin x を計算する for (x = 0; x <= 2PI; x = x + PI/10) printf("x = %5.3f, sin x = %6.3f n", x, sin(x)); x = 0.000, sin x = 0.000 x = 0.314, sin x = 0.309 x = 0.628, sin x = 0.588 x = 0.942, sin x = 0.809 x = 1.257, sin x = 0.951 x = 1.571, sin x = 1.000 x = 1.885, sin x = 0.951 x = 2.199, sin x = 0.809 x = 2.513, sin x = 0.588 x = 2.827, sin x = 0.309 x = 3.142, sin x = 0.000 x = 3.456, sin x = -0.309 x = 3.770, sin x = -0.588 x = 4.084, sin x = -0.809 x = 4.398, sin x = -0.951 x = 4.712, sin x = -1.000 x = 5.026, sin x = -0.951 x = 5.341, sin x = -0.809 x = 5.655, sin x = -0.588 x = 5.969, sin x = -0.309 x = 6.283, sin x = -0.000 続行するには何かキー...
標準ライブラリ関数を用いたプログラムの例 (2) 21 文字の文字列 s[] で #include <stdio.h> 1 文字だけを '' にして, #include <math.h> グラフとして表現する #include <string.h> #define PI 3.1415 #define amp 10 要素数 22の配列 double x, y; 文字列なので最後 int p; は0にしておく char s[2amp + 2]; s[2amp + 1] = 0; for (x = 0; x <= 2PI; x = x + PI/10) 全て空白文字で埋めておく _strset(s, ' '); y = sin(x); p = (int)(amp y + 0.5) + amp; s[p] = ''; printf("%s n", s); y=-1.0 s[0] 10 文字 (= amp) y = sin x のyに対応するインデックスを求める y=0 s[10] 10 文字 (= amp) s[20] y=1.0 y x 続行するには何かキー...
キャストによる変数型の変換 #include <stdio.h> int a = 2, b = 3; double x1, x2, y1, y2; x1 = 1 / 3; x2 = a / b; printf("x1 =%5.2f, x2 =%5.2f n", x1, x2); y1 = 1.0 / 3; y2 = (double) a / b; printf("y1 =%5.2f, y3 =%5.2f n", y1, y2); x1 x1 = 0.00, 0.00, x2 x2 = 0.00 0.00 y1 y1 = 0.33, 0.33, y3 y3 = 0.67 0.67 続行するには何かキー... 整数同士の演算では少数以下は切り捨て 1/3 = 0.333 0 浮動小数点と整数の演算では全て浮動小数点として計算 1.0/3 = 1.0/3.0 0.333 キャストの書き方 ( 変数型 ) 変数変数を変数型に変換する キャストによる型の変換
キャストを用いた四捨五入 #include <stdio.h> int c0, c1, c2, c3, c4; double x1, x2; x1 = 3.4999; c0 = x1; c1 = (int) x1; x2 = 3.5000; c2 = (int) x2; printf("c1 = %d, c2 = %d n", c1, c2); c3 = (int) (x1 + 0.5); c4 = (int) (x2 + 0.5); printf("c3 = %d, c4 = %d n", c3, c4); c1 c1 = 3, 3, c2 c2 = 3 c1 c1 = 3, 3, c2 c2 = 4 続行するには何かキー... warning C4244: '=' : 'double' から 'int' への変換です データが失われる可能性があります キャストを用いているので警告が出ない! キャストを用いた四捨五入 0.5 を足して整数型に変換すると小数以下の四捨五入になる 3.4999 + 0.5 = 3.9999 3 3.5000 + 0.5 = 4.0000 4
標準ライブラリ関数を用いたプログラムの例 (3) #include <stdio.h> RAND_MAXは #include <stdlib.h> stdlib.h 内でマクロ として定義されている int i; printf("0から %dの乱数 n", RAND_MAX); for (i = 0; i < 20; i++) printf("%d, ", rand()); printf(" n0から9の乱数 n"); for (i = 0; i < 20; i++) printf("%d, ", (int)((double)rand()/(rand_max+1)10); printf(" n0から9の乱数 ( 簡易的な方法 ) n"); for (i = 0; i < 20; i++) printf("%d, ", rand()%10); printf(" n"); 0 から 32767 の乱数 41, 18467, 6334, 26500, 19169, 15724, 11478, 29358, 26962, 24464, 5705, 28145, 2 3281, 16827, 9961, 491, 2995, 11942, 4827, 5436, 0 から 9 の乱数 9, 4, 1, 0, 0, 3, 5, 5, 5, 5, 1, 6, 4, 3, 1, 5, 7, 7, 5, 3, 0 から 9 の乱数 ( 簡易的な方法 ) 3, 1, 2, 3, 3, 4, 1, 1, 3, 8, 7, 4, 2, 7, 7, 9, 3, 1, 9, 8, 続行するには何かキー... rand() RAND_MAX+1 10 を計算する 0, 1,... 9 が同じ確率で現れる 0, 1,... 9 が同じ確率で現れない
標準ライブラリ関数を用いたプログラムの例 (4) #include <stdio.h> #include <string.h> #define mojisu 20 char s1[mojisu] = "abcdef"; char s2[mojisu]; int n; while(1) printf("%d 文字の文字列を当てよう!:", strlen(s1)); scanf("%s", s2); n = strcmp(s1, s2); if (n == 0) printf(" 正解です! n"); break; 66 文字の文字列を当てよう!:abcdee!:abcdee else if (n > 0) 辞書順でもっと後だよ!! printf(" 辞書順でもっと後だよ! n"); 6 else 6 文字の文字列を当てよう!:abcdeg!:abcdeg 辞書順でもっと前だよ printf(" 辞書順でもっと前だよ! n");!! 6 6 文字の文字列を当てよう!:abcdef!:abcdef 正解です正解です!! 続行するには何かキー......