プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機言語演習Ⅰ, 情報処理言語Ⅰ(実習を含む。) C言語入門 第5週 プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機言語演習Ⅰ, 情報処理言語Ⅰ(実習を含む。)
入れ子の繰り返し(多重ループ)
多重ループとは? ループの中に別のループを入れた 入れ子構造のループ mul99_ex1.c mintty + bash 7 8 9 10 11 12 for (i = 1; i <= 9; i++) { //行ループ for (j = 1; j <= 9; j++) {//列ループ printf(" %2d", i * j); //掛算九九 } printf("\n"); //行末尾で改行 $ gcc mul99_ex1.c && ./a 1 2 3 4 5 6 7 8 9 2 4 6 8 10 12 14 16 18 3 6 9 12 15 18 21 24 27 4 8 12 16 20 24 28 32 36 5 10 15 20 25 30 35 40 45 6 12 18 24 30 36 42 48 54 7 14 21 28 35 42 49 56 63 8 16 24 32 40 48 56 64 72 9 18 27 36 45 54 63 72 81 上記は掛算九九を計算して表を作成する例
掛算九九の例 見出し行と見出し列、見出し区切り(-+|)を付けた例 mul99_ex2.c mintty + bash 7 8 9 10 11 12 13 14 15 16 17 printf(" |"); //見出しの区切り for (j = 1; j <= 9; j++) { printf(" %2d", j); //見出し } printf("\n"); //見出しの改行 printf("--+"); //見出しの区切り printf("---"); //見出しの区切り printf("\n"); //見出しの区切りの改行 $ gcc mul99_ex2.c && ./a | 1 2 3 4 5 6 7 8 9 --+--------------------------- 1| 1 2 3 4 5 6 7 8 9 2| 2 4 6 8 10 12 14 16 18 3| 3 6 9 12 15 18 21 24 27 4| 4 8 12 16 20 24 28 32 36 5| 5 10 15 20 25 30 35 40 45 6| 6 12 18 24 30 36 42 48 54 7| 7 14 21 28 35 42 49 56 63 8| 8 16 24 32 40 48 56 64 72 9| 9 18 27 36 45 54 63 72 81
掛算九九の例 見出し行と見出し列、見出し区切り(-+|)を付けた例 mul99_ex2.c mintty + bash 19 20 21 22 23 24 25 for (i = 1; i <= 9; i++) {//行ループ printf("%2d|", i); //見出しと区切り for (j = 1; j <= 9; j++) {//列ループ printf(" %2d", i * j); //掛算九九 } printf("\n"); //行末尾で改行 $ gcc mul99_ex2.c && ./a | 1 2 3 4 5 6 7 8 9 --+--------------------------- 1| 1 2 3 4 5 6 7 8 9 2| 2 4 6 8 10 12 14 16 18 3| 3 6 9 12 15 18 21 24 27 4| 4 8 12 16 20 24 28 32 36 5| 5 10 15 20 25 30 35 40 45 6| 6 12 18 24 30 36 42 48 54 7| 7 14 21 28 35 42 49 56 63 8| 8 16 24 32 40 48 56 64 72 9| 9 18 27 36 45 54 63 72 81
while 文の2重ループの例 2重ループ while (条件式1) { // 処理1-1 while (条件式2) { // 処理2 // ... } // 処理1-2 条件式1 条件式2 偽 偽 真 真 処理1-1 処理2 1 2 2 処理1-1 ループは基本的にいくつでも 入れ子に出来る。
while 文の3重ループの例 3重ループ while (条件式1) { // 処理1-1 while (条件式2) { // 処理2-1 // 処理3 } // 処理2-2 // 処理1-2 条件式1 条件式2 条件式2 偽 偽 偽 真 真 真 処理1-1 処理2-1 処理2 1 2 3 4 3 処理1-1 処理2-1 入れ子があまり深くなると 分かり辛くなるので注意 4
異なるループ文で多重ループ do-while, while, for ループを必要に応じて組み合わせて入れ子にする 異なるループ文で3重ループ 異なるループ文で3重ループ for (式1-1; 式1-2; 式1-3) { // 処理1-1 while (条件式2) { // 処理2-1 do { // 処理3 } while (条件式3); // 処理2-2 } // 処理1-2 do { // 処理1-1 for (式2-1; 式2-2; 式2-3){ // 処理2-1 while (条件式3) { // 処理3 } // 処理2-2 // 処理1-2 } while (条件式1);
多重ループの例題 掛算九九の表
演習: 掛算九九(範囲指定) 標準入力から掛算九九の表の表示範囲 i1 i2 j1 j2 を読み取り、指定された範囲のみ表示する mul99_practice_1.c を作成せよ(/*WYCH*/ の個所を修正すれば良い)。 mintty + bash $ gcc mul99_practice_1.c && ./a i1 i2 j1 j2 = 2 5 4 8 | 4 5 6 7 8 --+--------------- 2| 8 10 12 14 16 3| 12 15 18 21 24 4| 16 20 24 28 32 5| 20 25 30 35 40 値が3桁やマイナスになると 表示が破綻する場合があるが、 以下で行う一連の演習では 3桁やマイナスの値は考慮しなくて良い。
演習: 掛算九九(行の反転) 完成した mul99_practice_1.c をコピーしてファイル名を mul99_practice_2.c とし、行の見出しが逆順となるよう修正せよ。 mintty + bash $ gcc mul99_practice_2.c && ./a i1 i2 j1 j2 = 2 5 4 8 | 4 5 6 7 8 --+--------------- 5| 20 25 30 35 40 4| 16 20 24 28 32 3| 12 15 18 21 24 2| 8 10 12 14 16
演習: 掛算九九(見出しの移動) 完成した mul99_practice_2.c をコピーしてファイル名を mul99_practice_3.c とし、列の見出しを表の下に表示するよう修正せよ。 mintty + bash $ gcc mul99_practice_3.c && ./a i1 i2 j1 j2 = 2 5 4 8 5| 20 25 30 35 40 4| 16 20 24 28 32 3| 12 15 18 21 24 2| 8 10 12 14 16 --+--------------- | 4 5 6 7 8
演習: 掛算九九(表示値の制限) 完成した mul99_practice_3.c をコピーしてファイル名を mul99_practice_4.c とし、i*j<=99の場合以外は結果を "##" と表示するよう修正せよ。 mintty + bash $ gcc mul99_practice_4.c && ./a i1 i2 j1 j2 = 8 14 5 15 14| 70 84 98 ## ## ## ## ## ## ## ## 13| 65 78 91 ## ## ## ## ## ## ## ## 12| 60 72 84 96 ## ## ## ## ## ## ## 11| 55 66 77 88 99 ## ## ## ## ## ## 10| 50 60 70 80 90 ## ## ## ## ## ## 9| 45 54 63 72 81 90 99 ## ## ## ## 8| 40 48 56 64 72 80 88 96 ## ## ## --+--------------------------------- | 5 6 7 8 9 10 11 12 13 14 15
多重ループの例題 画像の生成
BMP, DIB Wikipedia / Windows bitmap Windows 標準の画像形式 書くのは比較的簡単 例: 第1週の bmptest.c 等 読むのは、フォーマットがいくつもあるので、全部対応するのは面倒
PNM(Portable aNyMap) Wikipedia / PNM (画像フォーマット) シンプルなフォーマットで読み書きが簡単 ファイル識別子 画像形式 データ形式 P1 PBM: Portable Bit Map テキスト P2 PGM: Portable Gray Map P3 PPM: Portable Pix Map P4 バイナリ P5 P6 f.pbm P1 # f.pbm 6 7 0 0 0 0 0 0 0 1 1 1 1 0 0 1 0 0 0 0 0 1 1 1 0 0
テキスト形式の PBM Format 2値(白黒)画像用 feep.pbm P1 # feep.pbm 24 7 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 0 0 1 1 1 1 0 0 1 1 1 1 0 0 1 1 1 1 0 0 1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 1 0 0 1 1 1 0 0 0 1 1 1 0 0 0 1 1 1 0 0 0 1 1 1 1 0 0 1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 1 1 1 1 0 0 1 1 1 1 0 0 1 0 0 0 0 ファイル識別子 コメント 画像サイズ(幅と高さ) 2値画像データ本体 0または1のデータ
テキスト形式の PGM Format 濃淡値(グレイスケール)画像用 濃淡値画像データ本体 数値が大きいものほど明るい feep.pgm 24 7 15 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3 3 3 3 0 0 7 7 7 7 0 0 11 11 11 11 0 0 15 15 0 3 0 0 0 0 0 7 0 0 0 0 0 11 0 0 0 0 0 15 0 0 3 3 3 0 0 0 7 7 7 0 0 0 11 11 11 0 0 0 15 15 0 3 0 0 0 0 0 7 7 7 7 0 0 11 11 11 11 0 0 15 0 ファイル識別子 コメント 画像サイズ(幅と高さ) 明るさの最大値
テキスト形式の PPM Format カラー画像用 feep.ppm ファイル識別子 P3 # feep.ppm コメント 4 4 15 0 0 0 0 0 0 0 0 0 15 0 15 0 0 0 0 15 7 0 0 0 0 0 0 0 0 0 0 0 0 0 15 7 0 0 0 15 0 15 0 0 0 0 0 0 0 0 0 ファイル識別子 コメント 画像サイズ(幅と高さ) 明るさの最大値 カラー画像データ本体 RGBを1組にして書く
PNMからBMPへの変換 netpbm または ImageMagick を使うと楽 インストールは以下 Wikipedia / netpbm Wikipedia / ImageMagick インストールは以下 mintty + bash apt-cyg install netpbm apt-cyg install ImageMagick
PNMからBMPへの変換 ImageMagick を使った場合 $ ./a | convert - image.bmp パイプした結果を 標準入力から読み込む mintty + bash $ ./a | convert - image.bmp pnm を テキスト出力する プログラム 変換結果を保存する BMP ファイル名
演習: 円の描画(1/2) pbm_practice_1.c の /*WYCH*/ の箇所を修正し、中心座標(0,0)半径rの円の内部を0外部を1とし x1,x2,y1,y2 の範囲について P1 形式の PBM 画像を出力するプログラムを作成せよ。 ここでは円の内部を x 2 + y 2 < r 2 を定義し、境界部分は内部に含めない事とする。またx座標は右向き、y座標は下向きを正の方向とする。
演習: 円の描画(2/2) 出力結果の例 x1 x2 y1 (0,0) y2-y1+1 r y2 mintty + bash $ gcc pbm_practice_1A.c && ./a x1 x2 y1 y2 r = -5 5 -5 5 4 P1 11 11 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 1 1 1 1 1 0 0 0 0 0 0 0 1 1 $ gcc pbm_practice_1A.c && ./a | convert - result.bmp x1 x2 y1 y2 r = -5 5 -5 5 4
発展問題 pbm_practice_1.c を改造して■▲★等を描いてみよう
参考文献 [1] B.W.カーニハン/D.M.リッチー著 石田晴久 訳、プログラミング言語C 第2版 ANSI 規格準拠、共立出版(1989)