今回は,テキストデータにおける 文字種の検査とデータ型の変換について理解しよう.
テキストファイルや端末入出力(キーボード入力,画面出力)では, すべてのデータが文字列として取り扱われている. しかし,それらのデータをプログラムで処理する際には, 単純に文字列としてだけ取り扱えばよいわけではない. たとえば,まず「数字列」を入力し,「数値」に変換してから計算したり, 逆に,「数値」を計算し,「数字列」に変換してから出力する必要がある.
たとえば,scanf("%d %d", &x, &y) で2つの整数を入力する場合, この関数の内部では,次のような手続きが実行される:
このように,データの検査や変換は, テキストデータの入出力では必須の処理である.
文字の種類を調べるために,次のような標準ライブラリ関数が用意されている:
これらの文字種検査関数 is○○( ) はすべて, へッダファイル ctype.h の中で, 次のようにプロトタイプ宣言されている:
int is○○(int c);
なお,is○○() の戻り値は,検査条件が成立しない場合に 0, 成立する場合に 0 以外の整数となる. 使用方法と処理内容については, List 1 と List 2 を参考にしよう.
#include <stdio.h> #include <ctype.h> int main( ) { char *s = "otanoshike 2-32-1"; // 数字混じり文字列 while (*s != '\0') { if (isdigit(*s)) printf("%c", *s); // 数字だけ表示 s++; } printf("\n"); return (0); }
#include <stdio.h> //#include <ctype.h>// isdigit() のクローン int myIsdigit(int c) { if (c < '0') return (0); if (c > '9') return (0); return (1); } int main() { ... //if (isdigit(*s)) ...if (myIsdigit(*s)) ... ... }
数字列(文字列)から数値へ変換するためには, 次の標準ライブラリ関数を利用できる:
これらの変換関数のプロトタイプ宣言は, ヘッダファイル stdlib.h に記述されている.
では,変換関数について,仕組みを考えよう. List 3 は atoi( ) の基本的な(不完全な)定義例である.
#include <stdio.h> //#include <stdlib.h>// atoi() の不完全なクローン int myAtoi(char *s) { int value = 0; while (*s != '\0') { value = value*10 + (*s - '0'); // *s - '0' は,1個の数字を1桁の数値へ変換している. // value*10 は,数値の桁を繰り上げている. s++; } return (value); } int main() { char s[256]; int n; printf("整数 > "); scanf("%s", s); //n = atoi(s);n = myAtoi(s); printf("入力文字列:%s\n", s); printf("数値化結果:%d\n", n); return (0); }
なお,文字同士の引き算 *s - '0' については, ASCIIコード番号の計算であることに注意しよう.
逆の変換(数値から文字列への変換)については, 次の標準ライブラリ関数が便利だ:
sprintf(文字配列, 書式, ... )
この変換関数 sprintf( ) は, printf( ) の仲間であり, 書式付出力を画面表示する代わりに文字配列に書き込む. プロトタイプ宣言のへッダファイルは stdio.h である.
この関数 sprintf( ) には,たとえば,こんな使い道がある:
int x, w; char fmt[16]; printf("整数値と表示桁数 > "); scanf("%d %d", &x, &w); // ここでたとえば,x に 12,w に 5 を入力すると... sprintf(fmt, "%%0%dd\n", w); // 書式文字列が "%05d\n" となって... printf(fmt, x); // 出力は 00012 のように 5 桁になる
このテクニックは,表(table)を整形して表示する場合などに有効である.
List 3 を改造して,atoi( ) の完全なクローンを定義せよ.
条件:
変換例:(本来の atoi( ) の動作例)
ヒント:
アドバイス: atoi( ) の定義例は教科書にも掲載されているが, そちらのコードは高度過ぎる(わかりづらい)ので,パクりは禁止. 必ず,わかりやすいソースコードを書くこと.
特にループについては, 適切な方法(for と while)を使い分けること:
今回の課題には, while ループの方が適している. 入力された数字列の桁数は,検査するまで不明なので.
余裕のある人は,次のような関数も定義してみては?:
今回の課題では,まず, 1桁の 数字と数値について, ちがいを理解しないことには, 手出しできない. 例:
で,さらに,複数桁の場合には... 例: