1 C言語入門 第7週 プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機言語演習Ⅰ, 情報処理言語Ⅰ(実習を含む。) 2 吐き出し法(ガウスの消去法)のピボッティング 前回の復習 3 連立一次方程式を行列で計算する • 吐き出し法(ガウスの消去法) • ステップ1: 前進消去(上三角行列の作成) gaussian_elimination1.c // step1 for (k = 0; k < M - 1; k++) { for (i = k + 1; i < M; i++) { x = a[i][k] / a[k][k]; for (j = 0; j < N; j++) { a[i][j] = a[i][j] - a[k][j] * x; } b[i] = b[i] - b[k] * x; } } まずどこで ピボッティング処理するのが 良いのか考える 少なくとも、a[k][k]で割る 前でないと意味がないので 候補はこの3か所 4 連立一次方程式を行列で計算する • 吐き出し法(ガウスの消去法) • ステップ1: 前進消去(上三角行列の作成) gaussian_elimination1.c // step1 for (k = 0; k < M - 1; k++) { for (i = k + 1; i < M; i++) { x = a[i][k] / a[k][k]; for (j = 0; j < N; j++) { a[i][j] = a[i][j] - a[k][j] * x; } b[i] = b[i] - b[k] * x; } } k毎に処理しないと いけないので一番上は除外 k毎に処理しておけば i毎に処理する必要はない 従って一番下も除外 結果、真ん中が最適 と言うことになる 5 ピボッティング • a[k][k] が 0 か調べる gaussian_elimination1.c // step1 for (k = 0; k < M - 1; k++) { if (a[k][k] == 0) { // この場合にピボッティングする必要がある } for (i = k + 1; i < M; i++) { x = a[i][k] / a[k][k]; for (j = 0; j < N; j++) { a[i][j] = a[i][j] - a[k][j] * x; } b[i] = b[i] - b[k] * x; } } 6 ピボッティング • k+1行目以降でk列目が 0 でない行を探す gaussian_elimination1.c // step1 for (k = 0; k < M - 1; k++) { if (a[k][k] == 0) { for (i = k + 1; i < M; i++) { // ここでa[i][k]が0でない行を探す } } // ... } 7 ピボッティング • 目的の行を見つけた際の処理を書く gaussian_elimination1.c 授業では最初ここを // step1 a[i][k] == 0 for (k = 0; k < M - 1; k++) { としていたので、 if (a[k][k] == 0) { 上手く動いていませんでした。 for (i = k + 1; i < M; i++) { if (a[i][k] != 0) { // 目的の行を見つけた際の処理を書く } } } // ... } 8 ピボッティング • k行とi行の各列で値を交換する gaussian_elimination1.c // step1 for (k = 0; k < M - 1; k++) { if (a[k][k] == 0) { for (i = k + 1; i < M; i++) { if (a[i][k] != 0) { for (j = 0; j < N; j++) { // k行とi行の各列でaの値を交換する処理 } // k行とi行でbの値を交換する処理 } } } // ... } 9 ピボッティング • 暫定的に完成したピボッティング gaussian_elimination1.c if (a[k][k] == 0) { for (i = k + 1; i < M; i++) { if (a[i][k] != 0) { float tmp; for (j = 0; j < N; j++) { tmp = a[k][j]; a[k][j] = a[i][j]; a[i][j] = tmp; } tmp = b[k]; b[k] = b[i]; b[i] = tmp; } } } なぜ暫定的かと言うと このままだと、 二重にピボッティングする事もある。 実害はないが無駄な処理なので ピボッティングに成功したら そこでピボッティングの処理を 打ち切るほうが効率的。 10 continue 文、break 文によるループの再開と脱出 繰り返し(ループ)の復習 11 ループの再開と脱出 • continue 文 continue 文の2つ目の説明が微妙に間違ってました 正しくはループ末尾から再開 8週資料参照 • while, do while, for 文内で使用可能 • 以降の処理を中断してループを再開する • for文では後処理(第3パラメータ)も実行する • break 文 • while, do while, for, switch 文内で使用可能 • 以降の処理を中断してループを脱出する • switch文の場合はswitch文から脱出する 12 教科書 p.123. 後判定ループ (do while 文) • 真偽値による繰り返し continue break 処理 do { // 条件式 が真の場合の処理 } while (条件式); do while 文内の continue 文で 飛ぶ先が間違ってました 正しくは次項または 8週資料参照 真 条件式 偽 do while 文は、ループ内の処理を 最低1回は実行する。 13 教科書 p.123. 後判定ループ (do while 文) • 真偽値による繰り返し continue break 処理 do { // 条件式 が真の場合の処理 } while (条件式); 真 条件式 偽 do while 文は、ループ内の処理を 最低1回は実行する。 14 教科書 pp.124-129. 初期化・更新処理付きループ (for 文) • 真偽値による繰り返し 式1 for (式1; 式2; 式3) { // 式2が真の場合の処理 }; 式2 偽 真 continue 前判定ループだが 式1による初期化と 式3による更新処理を ひとまとめにして書ける。 処理 式3 break 15 教科書 pp.123-129. for文とwhile文 (前判定ループ) • 以下のループは等価 • continue時の式3の扱いに注意 for (式1; 式2; 式3) { // 式2が真の場合の処理 }; 式1; while (式2) { // 式2が真の場合の処理 式3; }; 式1 式2 while文の continue for文の continue 偽 真 処理 式3 break 16 教科書 pp.123-129. for文とwhile文 (前判定ループ) • 以下のループは等価 • continue時の式3の扱いに注意 for (i = 0; i < 10; i++) { // ループ内の処理 }; i = 0; while (i < 10) { //ループ内の処理 i++; }; i = 0 i < 10 while文の continue for文の continue 偽 真 処理 i++ break 17 教科書 pp.119-122. 後判定ループ (do while 文) • continue, break 後の処理(iの値)に注目 looptest_dowhile.c mintty + bash int i = 0, j = 0, n; $ ./looptest_dowhile n = 10 0, 1: 1st 2nd 3rd 1, 2: 1st continue 1, 3: 1st 2nd 3rd 2, 4: 1st 2nd break fprintf(stderr, "n = "); scanf("%d", &n); do { j++; printf("%d, %d: 1st", i, j); if (j == 2) {printf(" continue\n"); continue;} printf(" 2nd"); if (j == 4) {printf(" break\n"); break;} printf(" 3rd\n"); i++; } while (i < n); mintty + bash $ ./looptest_dowhile n = 0 0, 1: 1st 2nd 3rd do while 文は、 ループ内の処理を 最低1回は実行する。 18 教科書 p.123. 前判定ループ (while 文) • continue, break 後の処理(iの値)に注目 looptest_while.c mintty + bash int i = 0, j = 0, n; $ ./looptest_while n = 10 0, 1: 1st 2nd 3rd 1, 2: 1st continue 1, 3: 1st 2nd 3rd 2, 4: 1st 2nd break fprintf(stderr, "n = "); scanf("%d", &n); while (i < n) { j++; printf("%d, %d: 1st", i, j); if (j == 2) {printf(" continue\n"); continue;} printf(" 2nd"); if (j == 4) {printf(" break\n"); break;} printf(" 3rd\n"); i++; } mintty + bash $ ./looptest_while n = 0 19 教科書 pp.124-129. 初期化・更新処理付きループ (for 文) • continue, break 後の処理(iの値)に注目 looptest_for.c mintty + bash int i = 0, j = 0, n; $ ./looptest_for n = 10 0, 1: 1st 2nd 3rd 1, 2: 1st continue 2, 3: 1st 2nd 3rd 3, 4: 1st 2nd break fprintf(stderr, "n = "); scanf("%d", &n); for (i = 0; i < n; i++) j++; printf("%d, %d: 1st", if (j == 2) {printf(" printf(" 2nd"); if (j == 4) {printf(" printf(" 3rd\n"); } { i, j); continue\n"); continue;} break\n"); break;} mintty + bash $ ./looptest_for n = 0 20 余談 教科書 pp.265-272. [1] pp.139-144. 21 コマンドライン引数 • main 関数の引数として取得出来る。 argtest.c #include <stdio.h> #include <stdlib.h> int main(int argc, char *argv[]) { int i; main の引数名は 自由につけて良いが 以下の名前を使うのが 慣例になっている argc: ARGument Count argv: ARGument Vector printf("argc = %d\n", argc); for (i = 0; i < argc; i++) { printf("argv[%d] = \"%s\"\n", i, argv[i]); } return EXIT_SUCCESS; } argument は英語で 引数を意味する 教科書 pp.265-272. [1] pp.139-144. 22 コマンドライン引数 • main 関数の引数として取得出来る。 コマンドプロンプト >argtest a b "c d" "e\"f" argc = 5 argv[0] = "C:\Users\kou\Desktop\CLangI2014S1\argtest.exe" argv[1] = "a" argv[2] = "b" argv[3] = "c d" argv[4] = "e"f" mintty + bash $ ./argtest a b "c d" "e\"f" argc = 5 argv[0] = "./argtest" argv[1] = "a" argv[2] = "b" argv[3] = "c d" argv[4] = "e"f" コマンドライン空白で分割されて argvに格納される。 argvに空白を含めたい場合は 「"」(ダブルクォーテーション)で囲む 「"」を含めたい場合は「\」でエスケープする argv[0]は実行中のコマンド名 [1] pp.196, 199, 218. 標準入出力と標準エラー出力 • 以下の入出力が利用できる • stdin: STanDard INput: 標準入力 • stdout: STanDard OUTput: 標準出力 • stderr: STanDard ERRor output: 標準エラー出力 • scanf や getchar 等は stdin から入力している • printf や putchar 等は stdout へ出力している • stdin, stdout はパイプやリダイレクトの対象だ が stderr は標準では対象外 23 24 [1] pp.196, 199, 218. 標準入出力と標準エラー出力 • パイプやリダイレクトで処理されたくない内容 は stderr へ出力する • fscanf や fprintf を使うと、入出力先を自由に 選択出来る stdiotest.c mintty + bash printf("output to stdout with printf\n"); fprintf(stdout, "output to stdout with fprintf\n"); fprintf(stderr, "output to stderr with fprintf\n"); $ ./stdiotest > redirect.txt output to stderr with fprintf $ cat redirect.txt output to stdout with printf output to stdout with fprintf [1] pp.196, 199, 218. 標準入出力と標準エラー出力 • stdin,stdout,stderrはstdio.hで定義されている • stdio.h は standard input / output header 25 26 教科書 pp.61, 64-66, 98, 300. fprintf 関数 • int fprintf(FILE *fp, const char *FORMAT, ...); • printfの結果をfpへ書き出す • 引数: • fp: • FORMAT: • ...: FILE 構造体へのポインタ 書式 任意の数の引数 • 戻り値: • 書き出された文字数 • エラーの場合負の数 参考: [1] pp.305-306. 27 教科書 pp.80-83, 254. fscanf 関数 • int fscanf(FILE *fp, const char *FORMAT, ...); • fpからデータを読み込む • 引数: • fp: • FORMAT: • ...: FILE 構造体へのポインタ 書式 任意の数の引数 値を格納する変数へのポインタ • 戻り値: • 変換され代入された入力項目の数 • ファイル終端またはエラーの場合EOF 参考: [1] pp.307-309. 28 教科書 pp.298-305. fopen 関数 • FILE *fopen(const char *filename, const char *mode); • ファイルを開き、FILE構造体へのポインタを得る • 引数: • filename: ファイル名(パス)の文字列 • mode: ファイルを開くモード • 戻り値: • FILE 構造体へのポインタ • エラーの場合 NULL 参考: [1] pp.194-198. 29 教科書 pp.298-305. fopen 関数の mode mode 読み込み 書き込み 動作 "r" 任意の位置 × ファイルを開く、存在しない場合エラー "w" × 任意の位置 ファイルを作成し、前の内容は消去する "a" × ファイル末尾 ファイルを開く、または作成 "r+" 任意の位置 任意の位置 ファイルを開く、存在しない場合エラー "w+" 任意の位置 任意の位置 ファイルを作成し、前の内容は消去する "a+" 任意の位置 ファイル末尾 ファイルを開く、または作成 "r", "w", "a", "r+", "w+", "a+" はテキストモードで読み書きする テキストモードでは改行コード(\n)の扱いが環境によって異なる • Windows: CR LF (0xd 0xa) • Mac: CR (0xd) • UNIX: LF (0xa) バイナリモードにするには、"rb", "wb", "ab", "r+b", "w+b", "a+b" のように "b" を追加する 参考: [1] pp.194-198. 30 教科書 pp.298-305. fclose 関数 • int fclose(FILE *fp); • ファイルを閉じます • 引数: • fp: FILE構造体へのポインタ • 戻り値: • 0 を返す • エラーの場合 EOF を返す 参考: [1] pp.194-198. 31 演習 32 演習: print_0.c • 0を表示せよ • 数値の直後で改行すること コマンドプロンプト >print0 0 > 第3週資料 pp.23-33, 34-42. 演習: print_dec.c • scanf関数を用いてキーボードから入力され た整数をint型の変数iに読み込み10進数と して表示せよ mintty + bash $ ./print_dec • i を入力する前に「i = 」と i = 123 123 標準エラー出力に表示する事 33 34 第3週資料 pp.23-33, 34-42. 演習: print_octdechex.c • scanf関数を用いてキーボードから入力された 8,10,16進数の整数をint型の変数iに読み込 み8,10,16進数の3種類の表示せよ • i を入力する前に「i = 」と mintty + bash 標準エラー出力に表示する事 $ ./print_octdechex i = 0123 • 8進数表示の前には0を表示せよ 0123 83 • 16進数表示の前には0xを表示せよ 0x53 $ ./print_octdechex i = 123 • 各数値は幅6桁で右寄せで表示し 0173 末尾は改行すること 123 8,16進数頭の0,0xは6桁に含める $ 0x7b ./print_octdechex i = 0x123 0443 291 0x123 35 演習: print_evenodd.c • iが偶数か奇数か調べ以下の文字列を printf関数に与えて表示せよ • 偶数の場合: "even number\n" • 奇数の場合: "odd number\n" • print_evenodd_tmp.c を print_evenodd.c にコピーし 指定の場所に作成する事 mintty + bash $ ./print_evenodd i = 1 odd number mintty + bash $ ./print_evenodd i = 2 even number 36 演習: print_natural_lt.c • n未満の非負整数(0を含む自然数)を小さい 順に全て表示せよ • 各数値の直後で改行すること mintty + bash • 変数はi,nのみを使うこと $ ./print_natual_lt • print_natural_lt_tmp.c を n0 = 10 1 元に、指定の場所に作成する事 2 3 4 5 6 7 8 9 37 演習: print_even_lt.c • 0以上n未満の偶数を小さい順に全て表示せ よ • 各数値の直後で改行すること mintty + bash • 変数はi,nのみを使うこと $ ./print_even_lt n = 20 • print_even_lt_tmp.c を 0 2 元に、指定の場所に作成する事 4 6 8 10 12 14 16 18 38 素数 • 1と自分以外に正の約数を持たない自然数 (正整数)で1でない数 • 調べたい数をiとすると、2以上i/2以下の整 数jの全てについてiが割り切れないことを確 認すれば良い。 39 演習: print_isprime.c • iが素数かどうか調べ以下の文字列をprintf関数に 与えて表示せよ • 非素数: "not prime number\n" • 素数: "prime number\n" • 変数はi,j,primeのみを使う事 • 変数は以下の目的で使う事 • i: 素数かどうか調べたい数 • j: 2以上i/2以下の正数 • prime: 素数判定用のフラグ 0=非素数,1=素数 • print_isprime_tmp.c を元に 指定の位置に作成せよ mintty + bash $ ./print_prime_lt n = 2 $ ./print_isprime i = 2 prime number $ ./print_isprime i = 3 prime number $ ./print_isprime i = 5 prime number $ ./print_isprime i = 7 prime number $ ./print_isprime i = 11 prime number 40 演習: print_isprime.c • 非素数の場合も確認 mintty + bash mintty + bash $ ./print_isprime i = 4 not prime number $ ./print_isprime i = 6 not prime number $ ./print_isprime i = 8 not prime number $ ./print_isprime i = 9 not prime number $ ./print_isprime i = 10 not prime number $ ./print_isprime i = -1 not prime number $ ./print_isprime i = 0 not prime number $ ./print_isprime i = 1 not prime number 合成数の場合 負の場合、 0及び1の場合 41 演習: print_prime_lt.c • • • • n未満の素数を小さい順に全て表示せよ 各数値の直後で改行すること 変数はi,j,n,primeのみを使う事 mintty + bash 変数は以下の目的で使う事 • i: 素数かどうか調べたい数 • j: 2以上i/2以下の数 • prime: 素数判定用のフラグ • print_prime_lt_tmp.cを元に 指定の位置に作成せよ $ ./print_prime_lt n = 30 2 3 5 7 11 13 17 19 23 29 42 フィボナッチ数列 • いわゆる黄金比の数列 𝐹0 = 0 𝐹1 = 1 𝐹𝑛+2 = 𝐹𝑛 + 𝐹𝑛+1 (𝑛 ≥ 0) 43 演習: print_fibonacci_n.c • フィボナッチ数列のうち最小のn個を小さい順に 表示せよ • 各数値の直後で改行すること • 変数は f0, f1, f2, i, n のみを使うこと • 各変数は以下の用途で用いる事 mintty + bash • • • • f0 = 𝐹𝑖 f1 = 𝐹𝑖+1 f2 = 𝐹𝑖+2 iは上記𝐹𝑖 の添え字の意味で0~n-1 までの整数 $ ./print_fibonacci_n n = 10 0 1 1 2 3 5 8 13 21 34 44 演習: print_fibonacci_lt.c • n未満のフィボナッチ数列を小さい順に全て表示 せよ • 各数値の直後で改行すること • 変数は f0, f1, f2, n のみを使うこと • 各変数は以下の用途で用いる事 mintty + bash • f0 = 𝐹𝑖 • f1 = 𝐹𝑖+1 • f2 = 𝐹𝑖+2 $ ./print_fibonacci_lt n = 40 0 1 1 2 3 5 8 13 21 34 45 参考文献 • [1] B.W.カーニハン/D.M.リッチー著 石田晴久 訳、プログラミング言語C 第2版 ANSI 規格準 拠、共立出版(1989)
© Copyright 2024 ExpyDoc