【C言語講座】第3回 小数と入力のはなし
閉じる
閉じる

新しい記事を投稿しました。シェアして読者に伝えましょう

×

【C言語講座】第3回 小数と入力のはなし

2015-09-25 23:06
    0.今回扱う内容

    今回は割とごちゃまぜです。前半は小数(double型)を扱う話、真ん中に複数の変数を扱う話とちょっと話しそびれた話を挟んで、後半は入力の話になります。
    混乱しそうなら、2章か3章の後あたりで一旦時間を置くといいと思います。

    1.double型の扱い方 ~ 小数を使ってみよう!
    2.明示的な型変換 ~ 整数を小数とみなす!
    3.複数の変数を扱う ~ 入れ物がいっぱい!
    4.ユーザーの入力を受け付ける ~ 実行結果が入力によって変わる!
    5.小数を入力する ~ またint型とはちょっと違う!


    1.double型の扱い方 ~ 小数を使ってみよう!

    前回の復習です。int型には「整数」、double型には「小数」が入るのでした。
    とはいえ、前回のコードで実際に扱ったのは「整数」(int型)のみでした。

    ここでは、double型の扱い方について説明します。int型とはちょっと違うので気をつけてください。


    int型の時とはちょっと違うのが分かりますか?

    まず、宣言が「double a;」となっています。これは「double型の変数aを宣言する(場所をとる)」という意味。intがdoubleに変わっただけで、特に難しくはありません。

    次に、代入する値が「3.14」に変わっています。小数の例を出したかっただけなのでこれも特に問題無いでしょう。

    最後に、printfの中身がちょっと変わっています。
    int型で%dだった部分が、%fとなっています。

    これは、そういう決まりだとしか言いようがないのですが、int型では「%d」、double型では「%f」を変数文字列として使います。
    ちなみにdはdecimal(十進法の)、fはfloating-point number(浮動小数点数)の略のようです。

    それでは、早速実行してみましょう。

    あれ、「3.14」を入れたはずなのに0が増えてる! と思いましたか?

    実は、printfの%fで小数を表示するときは、小数第6位まで表示するという決まりになっています。たとえ0でも、です。

    気持ち悪いという人は、「%f」を「%.2f」に書き換えてみてください。
    こうすると、小数第2位まで(3.14)が表示されます。同様に、「%.1f」なら「3.1」、「%.0f」なら「3」となります。
    つまり、「%f」は「%.6f」と同じような意味、ということになります。


    2.明示的な型変換 ~ 整数を小数とみなす!


    前回の最後に出したコードです。

    「3.333...」を期待したのに、「3」と表示されてしまいました。

    これは、aがint型だったために「3」という整数になってしまったのでしょう。
    では、aをdouble型にしたら「3.333...」になるでしょうか?

    実行結果:

    %fで表示したので「3.000000」となりましたが、実質「3」と変わりません。
    どうしたことでしょう。

    実は、「整数÷整数」の計算は、結果も整数になるという決まりがあります。
    つまり、10÷3=『3』 あまり 1 の『3』が答えとなるわけです。
    「a」に入れる前の、10/3の計算の時点で「3」が答えになってしまっているのですから、いくら「a」をdouble型にしようと答えは変わりません。

    この問題を解決する方法はいくつかあります。
    ただ、どちらにしろ「整数÷整数」でなくする必要があります。

    解決策の一つが次のコードです。

    実行結果:

    遂に「3.333333」という望んだ答えが得られました。

    コードが変わった箇所は一箇所だけ。
    「a = 10 / 3;」が「a = 10.0 / 3.0;」となりました。

    これはどういう意味かというと、「10」と書くとコンピュータは「整数」だとみなしますが、「10.0」のように、小数点が含まれていると、「小数」だとみなすわけです。

    ここは、理系のほうが逆に混乱しやすい箇所だと思います。本質はどうあれ、小数「っぽく」書けば、コンピュータは小数とみなします。

    これも気持ち悪いと思う人は、対応策があります。


    「10」や「3」の前に、(double)と書き足しました。結果は同じになります。

    (double)の直後にある数は、たとえ整数であろうと、小数だとみなされます。
    この(double)のようなモノを「キャスト演算子」と呼びます。

    なお、「整数÷整数」の場合だけ結果が整数になるので、「整数÷小数」や「小数÷整数」では結果は小数になります。
    つまり、小数っぽく書いたり、(double)をつけるのは片方だけで十分ということです。
    ただ、慣れるまでは両方つけたほうが分かりやすいかもしれません。


    3.複数の変数を扱う ~ 入れ物がいっぱい!

    いままで一つのプログラムの中では一つの変数しか扱ってきませんでした。
    この章では、複数の変数を扱う際の注意点などを説明していきます。

    まず、宣言について。

    複数の変数を扱う際は、宣言をその数だけ書かなくてはなりません。

    ただし、同じ型の変数をたくさん使う場合は、省略して次のように書けます(変数同士はカンマ「,」で区切ります)。

    次に、(これは変数一つでも同じですが)変数を宣言するときにあらかじめ数字を入れておくことができます(「初期化」と呼びます)。

    省略した書き方では、次のように初期化できます。

    次にprintfの扱い方です。例えば、aの中身が3、bの中身が5の時に「a=3,b=5」と表示させたいときは次のようにします。

    「%d」が増えて、後に置く変数も増えました。それだけです。
    printfでは、%dや%fを、" "の後に置かれた数字に、前から順番に置き換えていきます。
    まあこれはやっていくうちに慣れるでしょう。

    ついでに、ここで一つ話しそびれたことを話しておきます。
    いままで、「処理」→「出力」の流れが見やすいように、また型の意識を持ってもらうために、「a」という変数を挟んでコードを書いていましたが、例えば「3+5」の計算結果を表示するプログラムは次のようにも書けます。

    随分簡単になりましたね。
    つまり、printfのカンマの後に置くのは変数一つとは限らない、ということです。

    なお、「3+5」の代わりに「a+b」や「a*3」など、変数を含んだ計算式を入れることもできます。この場合、変数名の部分が変数の中身に置き換えられて計算されると考えればよいでしょう。

    例:

    printfの時点で、aの中身は1、bの中身は2になっているので、(1+2)×3が計算された上で、「%d」の部分がその計算結果に置き換えられます。

    即ち、実行結果は「9」となります。


    4.ユーザーの入力を受け付ける ~ 実行結果が入力によって変わる!

    今までのプログラムは、コードを書き換えないかぎり、ずっと同じ結果を表示するものばかりでした。
    ゲームもプログラムの一種ですが、何度やっても同じ結果になるゲームなんてつまらないですよね?

    この章では、今まで何度か出てきた「入力→処理→出力」の「入力」の部分を作っていきます。そもそも入力がないゲームってコントローラー繋いでないのと一緒ですね。機種によってはゲームが起動できるかすら怪しいレベル。

    早速コードを見てみましょう。

    ちょっと複雑になりました。順を追って見ていきます。

    「int a,b;」では、int型の変数a,bを用意しています(宣言)。

    次に、printfで「整数aを入力してください」と表示し、改行しています。
    そして、scanfという謎の命令があります。
    次も同様に「整数bを入力してください」と表示・改行され、またscanfがあります。

    最後に、「a+b=」の後に、aの中身とbの中身を足しあわせて表示し、改行してプログラムは終了します。

    さて、謎の命令「scanf」について説明しましょう。
    このコード例や章のタイトルから察せる通り、scanfは「入力を受け付ける」命令です。

    scanf("%d",&a);

    " "の中身の「%d」は見覚えがありますね。printfで使った、整数の変数文字列です。
    そして、" "の後にもprintfと同様に、変数「a」が置かれています。
    しかし、aの前にこれまた謎の「&」という記号が付いています。
    これを説明するのには少し長くかかりますが、お付き合いください。

    printfや、scanfは、役割を持った」だと思ってください。「ロボット」でもいいと思います。

    printfは、「文字列を渡すと表示してくれる人」です。その時、変数を一緒に渡すと、文字列の中に組み込んで表示してくれます。

    一方で、scanfは、「入力された数字を、変数に入れてくれる人」です。scanfで、" "の中に%d」を書くと、「int型の入力を受け取ってください」という意味になります。
    それと一緒に、「入力された数字を『どこに』入れればよいか」を伝えなくてはなりません。

    以前、「メモリは棚のようなもの。宣言では、棚の中からint型のスペースを探して場所を取り、『a』の場所だと言い張る」と表現しました。『どこに』というのはちょうどこの「『a』の場所」に当たります。

    変数が格納されている場所を伝えるには、変数の前に「&」をつけます。
    つまり「&a」というのは、「棚の中の『a』の場所」を表すわけです。「10番の棚」とか「5番ロッカー」みたいな。

    まとめると、「scanf("%d",&a);」は、「scanfさん、%d(int型の数字)を受け取って、その数字を『a』の場所(10番の棚)に入れてください」という意味になります。


    あやうく実行するのを忘れるところでした。結果は次のとおりです。

    なお、2行目と4行目ではそれぞれキーボードから「123」「456」と入力した後にEnterキーを押しています(数字は例なので好きな数字を入力して構いません)。
    なぜ「整数bを……」が2行目(123)の終わりに続いて表示されていないのか気になる人へ。ここではEnterキーが「改行」と「入力(scanf)の終了」の両方の意味で機能しています。そのため、printfなどで改行を指示していないのに、2/4行目が改行されているわけです。

    そして、5行目では2行目と4行目で入力した整数が足し合わされた結果が表示されています。


    5.小数を入力する ~ またint型とはちょっと違う!

    次に、先ほど書いたプログラムを実数(小数)用にバージョンアップしてみましょう。

    コードは以下の通りです。

    ちょっと変わりました。変わった箇所は順に、

    • 宣言のintがdoubleに(整数を入れる棚から小数を入れる棚に)
    • 説明用printfの中の説明文が「整数」から「実数」に(どうでもいい)
    • scanfの変数文字列が「%d」から「%lf」に
    • 結果表示用printfの変数文字列が「%d」から「%f」に

    一つ引っかかる点があります。printfで使う変数文字列は、int型の場合「%d」、double型の場合「%f」でした。
    これも残念ながら(特に初心者には)「決まり」と言うほかないのですが、scanfの場合に限り、double型の変数文字列は「%lf」を使います。面倒ですね。

    まとめます。

    • int型なら(printf・scanfとも)「%d
    • double型で、printfなら「%f
    • double型で、scanfなら「%lf

    一応気になる人向けに「%lf」の理由を説明しますが、「理論的な話はいらねぇ! 暗記するよ!」という人は読み飛ばしてください。

    これには「変数のサイズ」、つまり「棚の大きさ」が関係してきます。
    実はdouble型は「倍精度浮動小数点型」であり、これとは別にfloat型(単精度浮動小数点型)と呼ばれるものがあり、こちらにも小数を入れることができます(滅多に使いません)。日本語の名前から分かる通り、double型の棚は、float型の2倍の大きさになっています(そもそも「double」ですし)。
    そして、「%lf」(long float)はdouble型、「%f」はfloat型に対応します。
    scanfでは、「入力を受け取って棚に入れる」のでした。入力されたデータがdouble型のサイズの場合、「%f」では棚が小さすぎて溢れてしまいます。そういうわけでscanfでは「%lf」を使います。
    そう考えると、今度はprintfが「%f」で良い理由が気になります。
    printfは「渡したデータを画面に表示する」人でした。float型だろうとdouble型だろうとdouble型とみなして受け取ります(勝手にキャストされる)。大は小を兼ねるというやつですね。そのため、double型とfloat型を区別して指定する必要がなく、両方とも「%f」でよいということになります。
    ただ、あまりに混同する人が多いので、最近の環境では両方「%lf」でもいいよ、ということになっています。ただ、使い分けたほうが無難です。

    実行結果はこちら。

    先ほどのプログラムとほぼ同じなので予想通りといったところですかね。

    ちなみにaは円周率π、bはネイピア数(自然対数の底)eです。(どうでもいい)


    今回もお疲れ様でした。次回は条件分岐(if)について扱う予定です。多分だんだん面白くなってくると思うので、是非めげずについてきてください。


    広告
    コメントを書く
    コメントをするには、
    ログインして下さい。