C プログラミング 1( 再 ) 第 4 回 講義では C プログラミングの基本を学び 演習では やや実践的なプログラミングを通して学ぶ 1
前回の復習 関数を作る : 何を引数として どういう計算をし 何を返すか 関数についての注意 : * main 関数で使われている変数と同じ名前の変数があっても それらには何ら関係はない * 関数名と同じ変数は その関数内では使わないようにする ( 紛らわしさを少なくするため ) * 呼び出しされる前に定義がされていること * 配列を引数とする場合 配列のサイズは書かない 2
main 関数で使われている変数と同じ名前の変数があっても それらには何ら関係はない こんな解答があった : intnenrei(inta,, intz) { // gengou という仮変数も変数宣言もない 中略 int main(void) { if (gengou== H ) { char gengou; scanf( %c, &gengou); printf( 年齢は %d n, nenrei(a,b, )); // gengou は実引数に表れない 3
関数名と同じ変数は その関数内では使わない 間違いとは言えないが 紛らわしいのでやめた方がよい ( 値を返すための変数は その関数名と同じものを使わなければならない と勘違いしていないか?) 例 : int max(int arr[], int n) { int i, max=arr[0]; return max; 4
呼び出しされる前に定義がされていること 流儀 1. 教科書流 ( まず main 定義 ) プロトタイプ宣言を用いる int max(int arr[], int n); int main(void) { printf( max = %d n, max(ar,n)); int max (int arr[], int n) { 関数の定義 流儀 2. 主役 (main 関数 ) は最後に登場 int max (int arr[], int n) { int main(void) { printf( max = %d n, max(ar,n)); 関数呼び出し 5
配列を引数とする場合 配列のサイズは書かない 配列を引数とする関数の例 間違いの例 float dotproduct(float a[ ], float b[ ]) { 中途略 float dotproduct(float a[10], float b[num]) { 中途略 int main(void) { float x,ar1[num], ar2[num];.. x = dotproduct(ar1, ar2); int main(void) { float x,ar1[num], ar2[num];.. x = dotproduct(ar1, ar2); 6
なぜ関数を作るか 関数を組み合わせて より複雑な仕事ができるようにする 確実に動く関数から 複雑な動きをする関数に発展させる 大きな仕事を一つの関数で書く ( 作る ) よりも 小さいわかりやすく単純な仕事に分け ( 段取り 分割統治 ) それぞれを確実に動くようにして ( デバッグが容易 ) より大きな仕事が確実に動くようにするほうが 効率も作りやすさも上である! 7
コンピュータにおけるデータの表現方法 コンピュータの内部は2 進数で表現されている基本単位はビット (bit) 1ビットは一つの ON/OFF 状態の表現もしくは 0 か 1 という状態を表すコンピュータの処理は バイト (byte) 単位で処理 1 byte = 8 bits 8
数の表現方法 デジタル (digital) デジタル vs アナログ 離散 不連続 連続 昔は アナログ型コンピュータ というものがあった今のコンピュータは デジタル型コンピュータ すべての物事を デジタル (= 飛び飛びの値 ) として表現精度を高めることで問題を解決 9
コンピュータは有限の桁数を処理 50 の階乗を求めよ (1) C でプログラムする (2) Python で次を実行する : fact = 1 ; n=50 for i in range(1,n+1) : fact *=i print(n,"! =", fact) int main(void) { int i,fact=1,n=50; for(i=1; i<=n; i++) { fact *= i; printf("%d! = %d n", n, fact); return 0; C には 型 がある それぞれの型により表現できる範囲が決まっている 10
データには型がある Cの変数で記憶できるもの ( データ ) は基本的に数であるそれは整数 (integer) と浮動小点数 (floating point number) の2 種類 疑問 : 文字や配列 ( 文字列を含む ) はどうなの? ひとまずの解答 : 文字は 符号なしの整数 配列は ポインタ ( 記憶番地 ) でこれも内部的には符号なしの整数 11
いろいろな整数の表記法 符号なし整数例 : 5U 10 進数数字の並び例 : 123 16 進数先頭に 0x または 0X をつける 例 : 0xc8 8 進数先頭に 0 をつける例 : 0310 12
いろいろな数を表示してみよう printf の第 1 引数の書式指定において %d と書くと 対応する整数を 10 進表示 したが 8 進や 16 進で表示するのはどうするのか? 答 : %o とすると 8 進表示 %x で 16 進表示 #include <stdiu.h> int main(vuid) { int i; fur(i=1; i<=100; i++) printf("%5d %5u %5x n", i, i, i); return 0; 1 1 1 2 2 2 3 3 3 4 4 4 5 5 5 6 6 6 7 7 7 8 10 8 9 11 9 10 12 a 11 13 b 12 14 c 13 15 d 14 16 e 15 17 f 16 20 10 17 21 11 18 22 12 19 23 13 20 24 14 21 25 15 22 26 16 23 27 17 24 30 18 25 31 19 26 32 1a 13
オーバーフローについて オーバーフロー (overflow): 桁あふれ Cの数として表現できるものには限界がある 表現できる範囲を超えると正常な結果が得られない Cでは 整数を 2 進数 として内部表現していました int 型の変数で記憶できるのは32ビット=-2 31 ~ 2 31-1までの数を表現 参考 : 13! 6.227 *10 9 例 : 階乗計算プログラムで 10から20までの階乗計算を表示させてみよう ( ウェブ上の参考プログラム 階乗計算 参照 ) http://lang.sist.chukyo-u.ac.jp/classes/c/fact.c -2147483648 2147483647 2.15*10 9 14
浮動小数点数 C では float 型の数は次のような形で表現される (0.15625 を表す ): 0 0 1 1 1 1 1 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 31 30 23 22 0 符号 指数部 (8bits) 仮数部 (23bits) 124 127 = -3 1+1/2 2 =1+1/4 =1.25 1.25 * 2-3 = 0.15625 おおまかに言って 指数部で 2 の乗数を 仮数部で小数点以下の数 ( 精度 ) を表すこれで表現できる正の数のは 2-149 1.4 10-45 であり それよりも小さな数は 0 として扱われる --- アンダーフロー (undeflow) したがって 精度を気にしなければ 大きな数や小さな数は 対数 計算を用いる 15
小数点数の内部表現の表示プログラム 浮動小数点数を入力し その内部表現を 16 進数として表示する (warning は出るが動くはず ) #include <stdio.h> int main(void) { int i; printf( 小数点数? >"); scanf("%f", &i); printf("%x n", i); return 0; C: Users sirai C>float.exe 小数点数? >0.15625 3e200000 3 e 2 0 0 0 0 0 16
文字の表現方法 ASCII 文字セット ( ウェブ検索して調べてみよう ) ( 半角 ) アルファベットや数字 スペースなどの記号 ( キーボードに刻印されている日本語文字以外の文字 ) は 1 バイトで表現 A は数としては 0x41 a は 0x61 B は数としては 0x42 b は 0x62 0 は数としては 0x30 1 は数としては 0x31 17
いろいろな文字と数の関係を表示する #include <stdio.h> int main(void) { char c; for(c='a'; c<='z'; c++) printf("%c: t%5d %5o %5x n", c, c, c, c); printf("------------- n"); for(c='a'; c<='z'; c++) printf("%c: t%5d %5o %5x n", c, c, c, c); return 0; 出力結果 : A: 65 101 41 B: 66 102 42 C: 67 103 43 D: 68 104 44 E: 69 105 45 F: 70 106 46 G: 71 107 47 H: 72 110 48 ( 中途略 ) ------------- a: 97 141 61 b: 98 142 62 c: 99 143 63 d: 100 144 64 e: 101 145 65 f: 102 146 66 ( 以下略 ) 18
制御コードとエスケープ シーケンス 制御コード文字 数字 記号のようには 表示されない モノ例 : 改行 タブなどこれらを 表現する にはどうするか? よくある方法は n t r f のように とアルファベットの組み合わせ を用いて表す は ( 環境によっては \) 次の文字を特別扱いせよ を表す エスケープ文字 19
日本語の文字表現 アルファベットや数字 記号は 1バイトで表現可能 (100 個もないため ) それに対して日本語の文字は数千個 ( 常用漢字で2,136) 表現するには少なくとも2バイト必要加えてASCII コードとの両立が望ましい JIS コード (ISO-2022-JP)--- 通常 e $ B と e ( B というエスケープシーケンスではさまれた 2 バイトずつのコード Shift-JIS コード EUC コード Unicode --- UTF-8, UTF-16 20
宿題 ( 易しい ) (1) 整数を入力し その 8 進数と 16 進数それぞれの表現を返すプログラムを書いてみよう 実行例 : 青字は入力 数?> 123 8 進数 : 173 16 進数 : 7b (2) 16 進数を入力し その 10 進表現を返すプログラムを書こう 実行例 : 青字は入力 16 進数?> abcd 10 進数 :43981 21
宿題 ( 続き ) (3) ASCII コードについて調べよ文字を入力するとそのASCIIコードを返すプログラム 逆にASCIIコード ( 整数 ) を入力すると文字を返すプログラムを作ってみよ (4) 漢 字 はそれぞれ内部的にはどのような表現がされているか 調べるプログラムを書いてみよ (5) ( 多倍長ではない int の ) 整数としてあらわされる最大の数と最小の数 ( マイナスの数 ) をプログラムを書いて求めてみよ 22