• 【C言語講座】第5回 同じ作業を何度も繰り返す

    2015-09-29 00:502
    0.今回扱う内容

    今回は一貫して「繰り返し」について扱います。
    だんだん分岐やループが入って頭がこんがらがると思いますが、一つ一つ丁寧にゆっくり読み解いていけば難しくありません。

    ゆっくり行きましょうね。休み休み。

    1.インクリメントと複合代入演算子 ~ 「1増やす」の3通りの書き方
    2.while文による繰り返し ~ 条件が成り立つ限り、無限に繰り返す
    3.for文による繰り返し ~ 回数がわかるとき使うと便利!
    4.無限ループとbreak文 ~ ループをかちぬくぞ!
    5.繰り返しの入れ子 ~ 二つの変数を同時に動かす


    1.インクリメントと複合代入演算子 ~ 「1増やす」の3通りの書き方

    今回「繰り返し」について扱うにあたって、「変数の更新」という話をしなくてはなりません。

    今まで変数に入れてきたのは、「3や5など、プログラマーが予め入力した数字」か「他の変数の中身(および、それを計算したもの)」ばかりでした。

    しかし、実際のプログラミングでは、「変数を1増やす」とか「変数を1減らす」、あるいは「変数に3を掛ける」といった場面が多く出てきます。

    たとえば、ゲームの例で言うと、「キャラクターを右に進める」ということは、「キャラクターの場所の変数を少し増やす」ということにあたります。

    ここでは、そんな「変数の更新」のやり方を学びます。まずはコード例から。

    最初は宣言。「int a = 3;」なので、int型(整数)の変数『a』の場所をとって、3を入れています。

    次に、「a = a + 5;」という文があります。
    「『a=a+5』だったら式が成り立たないじゃん!」と思った方は、「『=』は『代入』を表す記号」というのを思い出しましょう。「等しい」は「==」でした。
    つまり、「a」の棚から中身を取り出して、それに5を足して、また「a」の棚に戻す、ということです。

    aに3を入れて、それを取り出して5を足して戻し、printfでaを表示させているので、結果はもちろん……

    となります。

    次は、「複合代入演算子」という話。
    たとえば、「a += 5;」なら「変数『a』の中身に5を足して、『a』に戻す」という意味になります。つまり、「a = a + 5;」と同じですね。
    複合代入演算子には、四則演算の演算子と対応した5種類があります。

    • 「a += 5;」 ……変数「a」の中身に5を足して、「a」に戻す
    • 「a -= 5;」……変数「a」の中身から5を引いて、「a」に戻す
    • 「a *= 5;」……変数「a」の中身に5を掛けて、「a」に戻す
    • 「a /= 5;」……変数「a」の中身を5で割って、「a」に戻す
    • 「a %= 5;」……変数「a」の中身を5で割った余りを「a」に戻す
    • 他にも種類はありますが普通の人は使わないと思います

    なお、「/=」の場合も「整数÷整数」は整数になります。

    最後に、「インクリメント」の話。
    プログラミングでは「1増やす」という場面が特に多く出てきます。
    「1増やす」は複合代入演算子を使って「a += 1;」と書けますが、これを更に簡単にした書き方があります。
    「a++;」と書けば、「『a』を1増やす」の意味になります。
    この「++」を「インクリメント演算子」と呼び、「1増やす」ことを「インクリメントする」と言います。

    その逆に、「1減らす」は「a--;」と書けます。こちらは「デクリメント」と呼ばれます。

    以上をまとめると、「『a』を1増やす」は

    • a = a + 1; (通常の代入)
    • a += 1; (複合代入演算子)
    • a++; (インクリメント演算子)

    の3通りで書けます。

    ここで練習。次のコードの実行結果を予想してみましょう。

    さて、予想はできましたか? 結果を先に出してしまうと面白くないので、まずは読み解いていきましょう。

    宣言の時点では、aに1が入っています。
    そして、「a = a + 2;」で、aの中身に2を足してaに戻すので、aの中身は3になります。
    次に、「a *=3;」でaの中身に3を掛けるので、aの中身は9になります。
    最後に「a++;」でインクリメントしてからprintfで表示するので……

    結果は次の通り。


    2.while文による繰り返し ~ 条件が成り立つ限り、無限に繰り返す

    この章からは「繰り返し」について扱いますが、その前に一つ学んでおかなくてはならない事があります。
    それは、「無限ループ」についてです。
    繰り返し、という分野の都合上、コードを少し間違えると、動作を無限に繰り返してしまう可能性があります。
    そんな時は、Ctrl+Cで強制的にプログラムの実行を止めることができます(Visual Studioの場合)。
    まあ、右上の×ボタンで終了してもそんなに問題は無いんですが、そうすると実行結果が画面に残らなくなるので、無限ループが発生してしまった原因がわからなくなってしまいます。

    この「最終手段」を頭に入れた上で、先に進みましょう。まずはコード例。

    さあ、読んでいきましょう。
    「int i=1;」はいつも通り「宣言」、つまり「int型(整数)の変数『i』の場所を取る」のでした。それと同時に、「i」に1を入れています。

    次が問題です。でも、if文と形だけは似ています。
    if文は、

    if (条件) {
    やりたいこと
    }

    なのに対し、この「while文」は、

    while (条件) {
    やりたいこと
    }

    になっています。
    タイトル通り、while文は「条件が成り立つ限り、中身を繰り返す」文です。
    フローチャートに直すと以下のようになります。

    つまり、

    • int型の変数「i」を宣言し、1を入れる
    • 条件「iは10以下?」→ iは1なので成立
    • printfで「i回目」、つまり「1回目」と表示し、改行
    • iをインクリメントし、iは2となる
    • 条件「iは10以下?」→ iは2なので成立
    • ……(iが10になるまで省略)
    • printfで「i回目」、つまり「10回目」と表示し、改行
    • iをインクリメントし、iは11となる
    • 条件「iは10以下?」→ iは11なので不成立
    • return 0;(終了

    という流れになります。難しいですか?

    実行結果は次の通り。

    つまり、このプログラムは「1回目」から「10回目」までを順に表示するプログラムでした。

    ちなみに、ループで動かす変数はi,j,k,……などと名前をつけるのが一般的なので、ここでもそれに従いました。


    3.for文による繰り返し ~ 回数がわかるとき使うと便利!

    前章ではwhile文による繰り返しを学びました。
    ただ、前章の例では「繰り返す回数」が事前にわかっていました。
    このような場合、便利な書き方があります。

    まずはコード例。

    見慣れない箇所は

    for (i = 1; i <= 10; i++){

    です。ここで扱う「for文」は、

    for (初期設定; 継続条件; 繰り返し式) {
    やりたいこと
    }

    という構造を持ち、実際に実行すると、

    という順番に実行されます。さっきのwhile文と同じですね。

    また、if文と同様に、for文も中身が1行なら省略した書き方があります。

    for (i = 1; i <= 10; i++) printf("%d回目\n",i);

    となります。

    実行結果は前章と同じなので省略します。

    ところで、while文の書き方でもfor文の書き方でも必ず最初に「変数の初期化」を行っています。「初期化なんかしなくても最初に入ってる数字はある決められた数になってるんじゃないの?」とお思いの方のために、こんなコードを実行してみます。

    実行しようとするとまずエラーが出て怒られます。
    それでも「無視」を押して実行させると、

    という感じで、でたらめな数が表示されます。

    これは、「変数は棚」のイメージがあれば簡単な話。
    変数の棚は他のプログラムも使うので、変数を宣言した段階、つまり場所をとった段階では、前のプログラムが使った状態のまま放置されているのです。ごちゃごちゃなまま。
    というわけで、新しく変数を宣言するときは、必ず初期化を行いましょう。
    ただし、後々何か数字を入れるのがわかっている場合はその限りではありません。


    4.無限ループとbreak文 ~ ループをかちぬくぞ!

    ここでは、「無限ループ」について学びます。
    先ほど「無限ループは実行が止まらなくなって怖い」という話をしましたが、無限ループもうまく使えば便利です。

    では、コード例。

    while文の条件に「1」と書かれています。
    実は、プログラムの内部では「条件成立」は「1」、「条件不成立」は「0」として扱われています。
    つまり、「while (1){」と書けば条件が常に成立するので、ループが無限に続くことになります。

    ではどうやってループを抜けだすのか?
    その答えが「if (a > 1000) break;」です。

    break;」はループを抜けだす、という命令です。
    なお、ループが入れ子になっている場合は一番内側のループだけを抜け出します。

    つまり、「if (a > 1000) break;」で、「もしaが1000より大きければ、ループを抜けだす」という意味になります。

    また、aは1からスタートし、ループを回るごとに「a *= 2;」でaが2倍になっていくので、1,2,4,8,16,32,……,512,1024,……と大きくなっていきます。
    aが1000より大きくなったらループを抜けるので、aが1024になった時点でループを抜けることになります。

    結果を見てみましょう。

    aが1024になった直後、printfを通る前にループを抜けるので、1024という数字は表示されません

    これなら、whileの条件に「a > 1000;」と書いても同じだと思う人も居ると思います。確かに結果は同じになりますが、もっと複雑なコードになると、こちらの書き方が見やすい場合がよくあります。
    また、break文は、whileの条件とは別に、例外的にループを抜けなくてはならない場合にも用いられるので、覚えておきましょう。


    5.繰り返しの入れ子 ~ 二つの変数を同時に動かす

    ここでは、「入れ子」について学びます。
    if文を入れ子にできる(ネストできる)のは既に学んだ通りですが、forやwhileもネストできます。それではコード例。

    ちなみにこれは、第1回の「インデント」の例で出したプログラムとほぼ同じものです。
    ついにここまでたどり着きましたね。

    ちょっと新しい事項が多いかもしれません。

    まず、宣言ではiとj、2つの変数を用意しています。

    そして、iを変数としたループの中にjを変数としたループが入っています。

    また、printfに「%3d」という見慣れない変数文字列が入っています。
    これは、元の数字がどうあれ必ず3桁に揃えて表示する、という変数文字列です。
    たとえば、「3」を表示するときも「 3」と表示され、縦が揃って見栄えが良くなります。
    実行結果を見れば多分意味はわかると思います。

    流れは次のようになります。

    forの部分をちょっと簡略化して書きました。意味はわかりますかね?
    ハンバーガーみたいなイメージで、上と下で挟まれた部分を繰り返します。

    実行結果は次の通り。

    小学校でよくある九九の表が表示されました。

    プログラムの実行順序を追っていくと次のようになります。

    • int型の変数「i」,「j」を用意する
    • iに1を入れる
    • 条件「iは10より小?」→ iは1なので成立
    • jに1を入れる
    • 条件「jは10より小?」→ jは1なので成立
    • 「i*j」、つまり「 1」を表示
    • jをインクリメント(jは2になる)
    • 条件「jは10より小?」→ jは2なので成立
    • 「i*j」、つまり「 2」を表示
    • ……
    • jをインクリメント(jは10になる)
    • 条件「jは10より小?」→ jは10なので不成立
    • printfで改行
    • iをインクリメント(iは2になる)
    • 条件「iは10より小?」→ iは2なので成立
    • jに1を入れる
    • 条件「jは10より小?」→ jは1なので成立
    • 「i*j」、つまり「 2」を表示
    • ……
    • iをインクリメント(iは10になる)
    • 条件「iは10より小?」→ iは10なので不成立
    • 終了

    となります。つまり、1の段を表示して改行、2の段を表示して改行、……と進みます。

    ちょっと難しいですかね? 繰り返し眺めていればそのうち理解できると思います。頑張りましょう。


    ここまで来ればプログラミングの基礎は身についたと思います。

    とはいえ、まだまだ実際に思い通りのプログラミングをするには知識が足りません。

    次回からは基礎を抜けてちょっと難しい話を扱います。

    とりあえず次回は基礎脱出記念として、今まで「おまじない」とか「当然書くべきもの」とみなしてきた「#include」だとか、「return 0;」とかの本当の意味を扱う予定です。


  • 広告
  • 【C言語講座】第4回 もしも○○なら××

    2015-09-27 17:42
    0.今回扱う内容

    今回は一貫して「条件分岐」について扱います。
    ノベルゲームなんかで「ルート分岐」って出てきますよね?
    それの基礎の基礎に当たるのが今回の内容です。

    1.ifとelseの条件分岐 ~ もしAならBする。でなければCする。
    2.もっと複雑な条件分岐 ~ もしAなら、Bする。Aでなく、さらにCならDする。
    3.アルゴリズムとフローチャート ~ コードの手順を考えよう
    4.論理演算子いろいろ ~ もし、AかBなら、Cする。


    1.ifとelseの条件分岐 ~ もしAならBする。でなければCする。

    身近なプログラムというとどうしてもゲームになっちゃうので、またゲームの例を出します。
    上下左右のボタンを押すと、キャラクターが上下左右に動くようなゲーム(シューティングとか?)を想像してみましょう。

    こうしたゲームでは「もし上ボタンが押されていたら、キャラクターを上に動かす」、「もし下ボタンが押されていたら、キャラクターを下に動かす」……といった判断が常にされています。

    ほかのゲームでも、「もしAボタンが押されていたら、キャラクターをジャンブさせる」、「もしYボタンが押されていたら、必殺技を出す」。
    もっと原始的な例で言えば、(二人での)じゃんけんで「もし相手がパーで、自分がチョキなら、勝ち」。……しつこいですかね?

    今回はこうした「もしAだったら、Bする」という処理の方法を扱います。

    まずはコード例から。

    さあ、まずは順に読んでみましょう。

    最初は宣言から。「int a;」で「int型の変数『a』を用意」しています。

    次にprintfで「整数を入力:」という説明文を表示します。ただし、今回は最後に改行(\n)が入っていません。つまり、直後のscanfによる入力は「整数を入力:」と同じ行で行われます。まあ実行結果を見れば意味はわかると思います。

    scanfによる入力では「%d」(整数)の入力を受け付けて、入力された数字を変数「a」に入れています。

    ここからが新しい内容です。一行ずつ見ていきます。

    if (a == 0){

    if」という名前や今回のテーマから分かる通り、「もし~なら」を判断するのがこの文です。
    その「~」にあたる条件は、( )の中身です。つまり、この場合の条件は「a == 0」です。

    「a」は変数、「0」はただの数字ですが、「==」は初めての記号ですね。
    これは「比較演算子」と呼ばれるものの一つです。比較演算子は、その左右にある数を比較するための記号で、以下のような種類があります。

    • 「==」……左右の数は等しいか?
    • 「!=」……左右の数は異なるか?
    • 「<」……左より右の方が大きいか?
    • 「>」……左より右の方が小さいか?
    • 「<=」……左より右の方が大きい、または等しいか?
    • 「>=」……左より右の方が小さい、または等しいか?

    「代入」の説明の時、「『等しい』という意味の記号は『=』とは別にある」と言いました。それがこの「==」です。
    つまり、「a == 0」は「aと0は等しいか?」という意味(条件)になります。

    更に遡って、「if (a == 0){」は「もし、aと0が等しいなら」という意味になります。

    そして、「もしAならBする」の「Bする」の部分は、{ }の中に書くことになっています。

    C言語では{ }で囲まれた部分をまとまりとみなし、中身は見やすいように少し右に寄せるのでした(インデント)。
    というわけで、次の行にはインデントがかかっています。
    そして、その行ではprintfで「ゼロだよ」と表示し、改行しています。

    次に、}で「もし、aと0が等しいなら」のまとまりが閉じられた後で、「else」と書かれています。
    単語の意味から推測できるかもしれませんが、「そうでない場合は」という意味です。

    そして、else{ }の中ではprintfで「ゼロじゃないよ」と表示し、改行しています。

    つまり、まとめるとこのプログラムは、
    scanfで入力された数字(a)が

    • もし、aと0が等しいなら、「ゼロだよ」と表示(+改行)する。
    • そうでない場合は(aが0でないときは)、「ゼロじゃないよ」と表示(+改行)する。

    というプログラムです。こう書くと単純ですね。

    分岐ごとに実行結果を示します。


    ちなみに、ifやelseの中身(条件に当てはまった時に実行されるモノ)が1行で済む場合は、

    上のように、{ }を省略して書くことができます。人によってはこっちのほうが分かりやすいかも……?

    また、elseがいらない場合(「もしAならBする」だけの場合)、else以下は書かないで大丈夫です。


    2.もっと複雑な条件分岐 ~ もしAなら、Bする。Aでなく、さらにCならDする。

    タイトルの通りのちょっと複雑な分岐を作ってみましょう。まずはコード例。

    前章のプログラムより分岐が一つ増えました。変わったところを一つずつ見ていきます。

    else if (a > 0) {
    printf("プラスだよ\n")
    }

    「else」は「そうでない場合は」、「if」は「もしAならBする」でした。
    というわけで、「else if」だと、「そうでない場合で、さらに、もしAならBする」となります。
    つまり、この「else if」のまとまりは、「aが0でなくて、さらに、aが0より大きければ、printfで『プラスだよ』と表示し、改行する」という意味になります。

    この場合、一見すると、「aが0でなくて」という条件は無意味に思えます。この問題については次章で説明します。とりあえず次に進みましょう。

    else if (a > 0) {
    printf("プラスだよ\n")
    }

    これも先程と同様に、「aが0でなくて、さらに、aが0より大きくもなくて、さらに、aが0より小さければ、printfで『マイナスだよ』と表示し、改行する」という意味になります。
    色々と無意味な判断が入っているような気がします。

    とりあえず実行しましょう。



    つまりこれは、scanfで入力された数字(変数『a』の中身)が

    • 0なら「ゼロだよ」
    • 正なら「プラスだよ」
    • 負なら「マイナスだよ」

    と表示するプログラムです。


    3.アルゴリズムとフローチャート ~ コードの手順を考えよう

    前章のコードの手順を「フローチャート」と呼ばれる図に直すと、次のようになります。


    この図では、四角□が「処理」を、ひし形◇が「判断」を、角が丸い四角が「開始と終了」を表します。

    次に、これと同じ結果になるコード例と、そのフローチャートを幾つか示します。

    コード例1:

    コード例2:

    コード例3:

    例1では、最後の「else if」での判断を外して、無条件で「マイナスだよ」と表示するようにしました。ゼロでもプラスでもなかったら、判断するまでもなくマイナスですからね。
    ちなみに、if・else if・elseの中身は1行ずつなので、次のように書いても大丈夫です。

    例2では、「else if」ではなく、すべて「if」で判定することにしました。
    ただし、プログラミングにおいて、判断を行う回数が多いと、「遅いプログラム」になってしまいます。
    例2では、入力されたのが0だろうとプラスだろうとマイナスだろうと、必ず3回の判断を通ることになります。
    一方で、例1なら、入力されたのが0なら1回、0以外なら2回の判断だけを通ることになります。
    とはいえ、この講座では「動けば勝ち」なので、別にどちらで書いても問題はありません。

    例3のフローチャートは、例1のものと同一です。しかし、コードが変わっています。
    このコードのように、{ }で囲まれたまとまりの中に、さらに{ }で囲まれたまとまりを入れることを「入れ子ネスト)」と呼びます。

    また、フローチャートのように、実際にコードを書くわけではなく、正しい結果を導く処理や判断の実行順序だけを表現したもののことを「アルゴリズム」と呼びます。

    NHK Eテレの「ピタゴラスイッチ」で「アルゴリズム体操」というのがありました。
    せっかくniconicoのブロマガで記事を書いているので、ニコニコ大百科の記事から引用すると

    アルゴリズムというとコンピュータープログラミングを思い浮かべる人が多いのではないかと思うが、ここでいうアルゴリズムは「手順」といった意味合いである。すなわち、「手を横に、あら危ない、頭を下げればぶつかりません」に象徴されるように、各自がばらばらな動きをしていたら衝突が避けられないような環境でも、みんなが同じ規則・アルゴリズムに従えば障害を回避できるのである。

    ニコニコ大百科「アルゴリズムこうしん」より

    だそうです。また、年1~2回やっている「大人のピタゴラスイッチ」でも「アルゴリズム」という言葉が取り上げられ、例として「(電車が駅についた時に)車掌さんがドアを開けて、このボタンを押して、安全を確認して、……」というようなアルゴリズムが挙げられていました。

    無駄話が過ぎましたね。そろそろ次の章に進みましょう。

    なお、このプログラムの場合、変数「a」をint型(整数)に限定する必要は特にありません。
    もし余力がある人は、double型(実数)に書き直してみましょう。
    もし、全部「マイナスだよ」になったらscanfの変数文字列あたりを疑ってみましょう。


    4.論理演算子いろいろ ~ もし、AかBなら、Cする。

    今回はあと一章ばかりお付き合いください。

    ここでは、タイトル通り「論理演算子」というものを扱います。
    具体的には次の三つ。

    • 「&&」……「and(かつ)」の意味。「A && B」なら「Aでもあり、Bでもある」。
    • 「||」……「or(または)」の意味。「A || B」なら「Aであるか、Bである」。
    • 「!」……「not(ではない)」の意味。「! A」なら、「Aではない」。

    ちなみに、「&」はShift+6、「|」はShift+「\」(キーボード右上)で入力できます。

    ここで注意して欲しいのは、喫茶店で「コーヒーか紅茶」と言われたら普通「コーヒーと紅茶の両方」という選択は想定されていませんが、プログラミングでは「AまたはB」と言えば普通「AかB、またはその両方」を意味する点です。

    コード例を見ていきましょう。

    まずは読んでいきます。

    見慣れない箇所は「a > 0 && a < 10」です。
    これは「aが0より大きく、さらに10より小さい」を意味します。
    ここでaはint型(整数)なので、「aは1,2,3,4,5,6,7,8,9のいずれか」と読み替えられます。
    つまりは「aは1桁の整数」ということになります。

    結果は次の通り。


    次は、逆に「一桁の正の数ではないよ」と表示するコードを書いてみましょう。
    変える箇所は「if」の条件と、中身のprintfで表示する文字です。

    表示する文字は「一桁の正の数ではないよ」に変えるだけなので簡単です。
    問題は「if」の条件の方。「ではない」は「!」でしたから、

    if (!a > 0 && a < 10)

    とすれば良いのでしょうか? 答えは次の通り。

    ( )が付きました。「『aは0より大きい かつ aは10より小さい』ではない」ということですね。

    先ほどの「if (!a > 0 && a < 10)」だと、「!」は直後の「a」だけに係るので、「『aではない』は0より大きい かつ aは10より小さい」という意味不明なことになります。

    なお、「aは0より大きい かつ aは10より小さい」は「aは0より大きくない または aは10より小さくない」と書いても同じなので、

    if (!(a > 0) || !(a < 10))

    と書いても大丈夫です。あるいは、「aは0以下 または aは10以上」、つまり

    if (a <= 0 || a >= 10)

    と書いても同じことになります。まあ、どれ書いても「動けば勝ち」ですよ。

    また、論理演算子も「+ - * / %」のような普通の演算子と同様に、「A && B || C」のような複雑な計算では「(A && B) || C」のように括弧をつけてわかりやすくしましょう。


    お疲れ様でした。次回は、「繰り返し」について扱う予定です。


  • 【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)について扱う予定です。多分だんだん面白くなってくると思うので、是非めげずについてきてください。