#pragma twice

KAB-studio > プログラミング > #pragma twice > 225 Version 12.02 数字と文字列の変換

#pragma twice 225 Version 12.02 数字と文字列の変換

前のページへ 表紙・目次へ 次のページへ

 Version 12.02
数字と文字列の変換

今回は、数値と文字列の変換について説明します
それって結構重要?
重要。たとえば 01.txt から 10.txt までのファイルを読み込む、ってい
う時にべたに書くよりは
 for 使って数字に変換した方が楽ってことね
そういうこと。そういう場合のためにってことで。まず、基本的な考え方
から。たとえば

    int i = 100;

ってあった場合、 int の中には 0x00000064 が入っています。これを

    char pch[256];

の中に文字列として 100 が入ってる場合

pch[0] == '1' == 0x31
pch[1] == '0' == 0x30
pch[2] == '0' == 0x30
pch[3] == \0  == 0x00

という感じになっていればいいわけ
それぞれの文字コードが1文字ずつ入ってる……でも int とかなり違う
よね
そう。でも、簡単に変換できると思わない?
どうやって?
まず、 100 を1桁ずつに分けて考えます
んー、最初の 1 だとすると、それを pch[0] に入れるわけで、それが 0x
31 になればよくて、…… 0 の時は 0x30 だから……あ、 0x30 足して入れ
ればいいの?
そういうこと。1桁ずつ取り出して 0x30 足すとそれが文字コードの 0 
や 1 になるから、そうしたら1文字ずつ入れていけばいいわけ
なるほど、簡単そう
実際にやると大変なんだけど
へ?
1文字ずつ取り出すの、どうすればいいと思う?
えーっと……
こうします

void GetFirst()
{
    int i = 105;
    // 5 だけ抜き出します。
    int i0 = i - ( ( i / 10 ) * 10 );
    TRACE( "%d\n", i0 );
    // 5
}

 10 で割って 10 で掛ける? それって一緒になるんじゃ
じゃないでしょ、 105 を 10 で割って 10 、 10 を掛けて 100 
1の位が 0 に……そか、それで引くと最初の桁だけ残るんだ!
そういうこと。で、これは1の位だけだから、実際のプログラムでは全部
の桁でしなきゃいけないし、桁数も取得しなきゃいけない
めんどー
だから普通はランタイム使います
……あるんじゃん
もちろん。というか使ったことあるでしょ。 sprintf() とか
あ! そういえば
 Version 5.07 ( No.072 ) でやったね。それに、 CString なら 
CString::Format() ってメンバ関数があるからそっちの方がいいかも
どう違うの?
ほとんど同じ。

void Use_Format()
{
    CString cStr;
    cStr.Format( "%d", 100 );
    TRACE( "%s\n", cStr );
    // 100
}

 %d とか、同じだね
 sprintf() も CString::Format() も、 TRACE() とかと同じ書式だか

ひとつ憶えれば大丈夫ってわけね
でも、微妙な部分もあるかな
微妙?
このタイプのものの一番の問題は、型のチェックがされないっていう点。
たとえば

void Use_Format_Bad()
{
    CString cStr;
    cStr.Format( "%s", 100 );
    // アクセス違反。
}

あ、 Access Violation だ
つまり、 100 って数字を文字列のポインタと見なしちゃうから
げ、それってまずいじゃん
そう、まずいわけ。これは TRACE() でも起きるよ

void Use_TRACE_Bad()
{
    TRACE( "%s\n", 100 );
    // アクセス違反。
}

ホントだ起きる……
これは TRACE() や sprintf() や CString::Format() が【可変長引数】
っていうのを使ってるから
かへんちょーひきすう?
その可変長引数のおかげで、いくつつでも引数を渡すことができるんで

あ……つまりそれって、オーバーロードとか使ってないってこと?
いろんな型の引数をいくつも、なんて考えたらすごい数の組み合わせにな
っちゃうでしょ
確かに。だからその可変長引数ってのを使ってるわけね。で、それは型の
チェックができない、と
ありとあらゆる型が渡されるんだからしょうがないんだけどね。で、そう
いった場合に代わりになるのが Version 5.17 ( No.082 ) で教えた 
std::strstream とか
あー、ストリーム系ね
こっちはちゃんと型チェックされてるから大丈夫。ただ、使われてる割合
はかなり少ないから
少なくても、使っちゃえばいいじゃん
前も言ったけど、 C 言語しか使えないときもあるから。これは C++ でし
か使えないからね
……他の人と合わせなきゃとか、そーゆーのね
でも使えるんなら使った方がいいから。安全性ならこっちの方が上だか

はーい
さて、ここまでは int を文字列にしてみました
……逆?
そう、今度は文字列を int にします
考え方って同じだよね。それぞれの文字で……今度は 0x30 を引けばいい
のかな
そうだね、文字を右から見ていって、 0x30 を引いて、あとは文字の位置
に合わせて 10 の何乗っていうのを掛ければいいかな
 10 の何乗?
右から2桁目なら 10 、3桁目なら 100 、4桁目なら 1000 を掛けて足
せば
そっか、それでできちゃうんだ
こっちの変換の方が簡単……と思うかもしれないけど、実はそうでもない
んです
ないの?
まぁその前に、まずランタイムを使った例から

void Use_atoi()
{
    int i = atoi( "100" );
    TRACE( "%d\n", i );
    // 100
}

こんな風に、ランタイムは atoi() を使えば変換できます
へー、簡単! でも〈えーとぅーあい〉って変な名前……
呼び方は色々あると思うけどね。 ASCII to Int の略だと思うよ
 ASCII ?
ほら、普通の英文字を ASCII 文字って言うって
 Version 5.04 ( No.069 ) でやったね。そか、普通の文字から数字に変
換、って意味ね
で、この関数にはひとつ問題があります

void Use_atoi_Bad()
{
    int i = atoi( "a" );
    TRACE( "%d\n", i );
    // 0
}

ん? 数字以外が入ってると 0 になるんだ
もし "0" を変換したら?
 0 ……どっちも 0 ?
そう、この関数は、 0 が入ってたのか、それとも変換できなかったのか
がわかんないんです
げげげ
一応、ランタイムに isdigit() っていうのがあって、これで1文字ずつ
チェックできます

void Use_isdigit()
{
    TRACE( "%d\n", isdigit( '1' ) );
    TRACE( "%d\n", isdigit( 'a' ) );
    // 4
    // 0
}

 4 ?
まぁ、数字だったら 0 以外ってことになってるから、 0 かそうじゃない
かで調べた方がいいかな
ん。これ使って……1文字ずつ調べるの?
それだと面倒だから、 std::strstream とか使った方がいいかも
そっちなら大丈夫? あ、そういえばファイルから取り出した時、 数字
とかじゃなかったら fail() がどうとかあったもんね
そういうこと。その辺の仕組みがあるから、ランタイムよりもいいかな。
まぁ関数ひとつで簡単に変換できるのは楽だけど
確かに std::strstream とかって使うの結構めんどいよね……
その辺も広まってない原因かも。ただ、こういう細かいところではまる事
って多いから、選択は気を付けてね

/*
    Preview Next Story!
*/
なんか今回って復習って感じ
それだけ憶えてきたことも多いってこと
そ?
でも憶えることはまだまだいっぱいあります

というわけで次回
< Version 12.03 パソコンは計算機 >
につづく!
次回からはかなり難しいです!
あう〜
 
del.icio.us 登録する
Yahoo!ブックマーク 詳細を表示 users
livedoorクリップ 詳細を表示 livedoorクリップ ブックマーク数
はてなブックマーク 詳細を表示 はてなブックマーク ブックマーク数
RSSに登録
del.icio.us 登録する
Yahoo!ブックマーク 詳細を表示 users
livedoorクリップ 詳細を表示 livedoorクリップ ブックマーク数
はてなブックマーク 詳細を表示 はてなブックマーク ブックマーク数
 
このページは、Visual C++ 6.0を用いた C++ 言語プログラミングの解説を行う#pragma twiceの一コンテンツです。
詳しい説明は#pragma twiceのトップページをご覧ください。