プログラミング及び実習 5 馬青 1
文字処理 数値処理 : 整数 浮動小数点数 単一の文字は と ( シングルクォーテーション ) で囲んで表現される 文字のデータ型は char または int である int を用いたほうが ライブラリの関数の引数の型と一致する 以下は全部 int の使用に統一する 従って int ch; で文字変数を宣言しておくと ch= A ; のように ch に文字 A を付与することができる (int ch= A ; で宣言するのも OK)! 注意 :ch=a; はだめ! 2
文字の入出力 キーボードからの入力は ch=getchar(); or scanf( %c, &ch); /* int で宣言の場合 warning message が出る処理系がある char で宣言すると warning message が出ない */ ディスプレイへの出力 putchar(ch); or printf( %c, ch); 3
空白文字 単一の文字として 空白文字 が色々なところに使われる 空白文字は以下のように与える ch= ; 出力は前に述べた方法で ch を出力することはできるが putchar( ); でも出力できる もちろん printf( ); でも OK 空白はよく判断文にも使われる :if(ch == )... 4
制御文字とは 上に述べた普通の文字以外に 制御文字と呼ばれるものがある 制御文字とは 出力のコントロールやそのままでは表現できない文字を扱うために用いられる 5
主な制御文字 制御文字使用例機能 n printf( n ); 改行し 次の行の先頭にいく t printf( t ); 水平タブ b printf( b ); 一文字分戻る r printf( r ); 同じ行の先頭に戻る f printf( f ); 改ページ またはスクリーンクリア printf( ); を出力する注意 :printf( ) ではだめ! printf( ); を出力する注意 :printf( ) ではだめ! printf( ); を出力する注意 :printf( ) ではだめ! linuxではバックスラッシュ 6
制御文字についての補足 制御文字は表面上 2 つの文字で表されているが 計算機内部では単一の文字 ( つまり同じバイト数 ) で表現されている 従って 普通文字と同様 int ch; ch= t ; 1 文字分 は OK である 以上のように制御文字を ch に付与すると 以下の 2 文は等価になる : printf( 制御文字 t 使用例 t 機能 n ); printf( 制御文字 %c 使用例 %c 機能 n, ch, ch); 7
英数字文字と整数値の対応 コンピュータ内部では 全ての文字は整数 ( 文字コード ) で表現されている ( 半角英数字や記号 ) 文字はアスキーコード表と呼ばれるものに従っている たとえば英数字は以下の通りに対応している 英字文字 数字文字 A, B,..., Z 65-90 a, b,... z 97-122 0,... 9 48-57 文字 整数値 8
Question (1)putchar( A );? (2)putchar(65);? (3)int ch= A ; printf( %c %d n, ch, ch);? (4)printf( %c %d n, A, A );? (5)printf( %c %d n, 65, 65);? (6)putchar(65+3);? (7)putchar(68);? (8)putchar( A +3);? (9)ch= D ; putchar(ch- A + a );? (10)putchar( D - A + a -2);? 9
演習問題 1 三つの文字変数を用いて任意の3 文字をキーボードから入力し それらに + 記号を挿入して出力するプログラムを書きなさい 実行例 : $./a.out abc 入力 +a+b+c 出力 10
プログラムの改良 前のプログラムの問題点の 1 つは 文字の数だけ 文字変数を用意しなければならない したがって 文字の数が多い場合は対処困難である たとえば 以下の例では 10 個の文字変数を用意しなければならない 実行例 : $./a.out abcdefghij +a+b+c+d+e+f+g+h+i+j 入力出力 11
プログラムの改良 #include <stdio.h> main() { int ch; while((ch=getchar())!= ' n') printf("+%c", ch); putchar(' n'); } 12
プログラムのさらなる改良 前のプログラムでは 一行が入力されると プログラムが終了してしまう 特殊なキーを押すまで 繰り返し入力ができるようにしたい 実行例 $./a.out abc 入力 +a+b+c 出力 opqxyz 入力 +o+p+q+x+y+z 出力 Ctrl-D 入力終了 13
プログラムのさらなる改良 #include <stdio.h> プログラム 1 main() { int ch; while((ch=getchar())!= EOF){ if(ch!= ' n') printf("+%c", ch); else printf(" n"); } } 14
プログラム 1 とプログラム 2 は 何が違う? プログラム 2 #include <stdio.h> main() { int ch; while((ch=getchar())!= EOF) printf("+%c", ch); } 15
2 の実行結果は以下になる 実行例 $./a.out abc +a+b+c+ opqxyz +o+p+q+x+y+z+ Ctrl-D 終了 最後に + が出力される 入力出力入力出力入力 16
演習問題 2 前のプログラム1を各入力文字を3 文字ずらす ( 例 :a d) ように修正しなさい ただし 文字はa~wの範囲内のものとする ( つまり x,y,zは除外する ) 実行例 $./a.out abc 入力 +d+e+f 出力 defghi 入力 +g+h+i+j+k+l 出力 Ctrl-D 入力終了 17
ファイルの複写プログラム #include <stdio.h> main() { int ch; while((ch=getchar())!= EOF) printf( %c, ch); // putchar(ch); } 18
ファイルの複写プログラム s.dat This is a test file. Ryukoku University Program Lecture./a.out<s.dat>o.dat o.dat This is a test file. Ryukoku University Program Lecture 19
例題 (1/2) 文字をキーボードから入力し 改行を入れた時点で 小文字を大文字 大文字 数字 改行記号はこのまま 特殊文字 ( 英数字 改行以外の文字 ) を空白に変換して出力するプログラム ただし Ctrl+D で終了とする 20
例題 (2/2) #include <stdio.h> main() { int ch; while((ch=getchar())!= EOF){ if(ch>= a && ch<= z ) // 小文字なら putchar(ch- a + A ); // 大文字に else if(ch>= A && ch<= Z ch>= 0 && ch<= 9 ch== n ) putchar(ch); // 大文字か数字か改行はそのまま else // 特殊文字なら putchar( ); // 空白に } } 21
注意 if(ch< a ch> z ) を用いて ( つまり小文字でなければ ) 大文字か数字であることを判断することはできない ( それ以外の文字かもしれない ) また 文字変換は必ずしも正確ではない if((ch< a ch> z ) && (ch< 0 ch> 9 )) // 小文字 数字ではない putchar(ch- A + a ); 22
第 5 回実習課題 (1/5) 1. 以下のようなプログラム (ex05-findpair.c) を作成しなさい (a) データ件数とデータをキーボードから入力し 変数 n と int 型配列 a に与える たとえば n: 11 a: 10 9 8 7 6 5 4 3 2 1 0 (b) 配列 aの任意 2つの ( 異なる ) 要素について 足し算と引き算のみを使って その計算結果が8となるすべてのペアを求める 解がないときは空行を出力し 解がある場合はそのすべてのペアを出力する たとえば上記の場合 10-2=8, 2+6=8なので (10, 2, -)(2, 6, +).. のように出力する なお (3,5,+) と (5,3,+) のような実質的に同じ内容のペアは両方を出力しても構わないとする また プログラムの構造については 一切制限ないとする 23
第 5 回実習課題 (2/5) 2. 大文字を小文字に 小文字を大文字に それ以外の文字はそのまま出力するプログラム (ex05.c) を作成しなさい ただし Ctrl-Dを押さない限り 文字列を繰り返し入力可能とする 実行例 : $./a.out A+b-c 入力 a+b-c 出力 1+2 入力 1+2 出力 a%& 入力 A%& 出力 Ctrl-D 入力終了 24
第 5 回実習課題 (3/5) 3. 課題 2 のプログラムを文字列の前後に括弧をつけて出力するようにプログラムを改良しなさい (ex05-adv.c) 実行例 : $./a.out A+b-c 入力 [a+b-c] 出力 1+2 入力 [1+2] 出力 a%& 入力 [A%&] 出力 Ctrl-D 入力 終了 25
第 5 回実習課題 (4/5) 課題 3のヒント : 左括弧をつけるために 先頭文字か先頭文字でないかの判定が必要 そのために たとえば fg=1が先頭でfg=0が先頭でないというように 状態変数 ( フラッグ ) を導入すると便利かも 今読み込んだ文字は改行文字かの判定も必要になってくる 改行文字であれば改行の前に右括弧をつけると同時に状態変数 fgの値を1に戻す必要がある ( つまり 次に読み込まれる文字はまた先頭文字になる ということ ) 26
発展課題 第 5 回実習課題 (5/5) 4. 任意に入力された文字列に対し 記号 +が挿入された以下のような逆順の文字列を出力するプログラム (ex05- addrev.c) を作成しなさい ただし Ctrl-Dを押さない限り 文字列を繰り返し入力可能とする 注意 : 挿入される記号と文字がペアにならないため 記号挿入に関しても例題とは違う ヒントとしてはたとえば int ch[100] のように 文字の一次元配列を使い 入力された文字列をいったん配列にためておき そして文字 ( 及び記号 ) を逆順に一つずつ出力する方法が考えられる 実行例 $./a.out abc 入力 c+b+a 出力 54321 入力 1+2+3+4+5 出力 Ctrl-D 入力 27 終了