わさっきhb

大学(教育研究)とか ,親馬鹿とか,和歌山とか,とか,とか.

ifとelseを使いこなそう~2. 序数の接尾辞

プログラムコードの前に,何をしたいかを書かないといけません.我々は英語で2種類の数を学んできたはずです.一つは,one, two, three, four, ...と数えていくもので,普通の数なのですが,「基数」と呼ばれます.もう一つの数は,first, second, third, fourth, ...と数えます.「序数」といいます.
いちいちスペルを書くのは面倒ですので,基数は1, 2, 3, 4, ...と表記するのが一般的です.それに対し除数については,1st, 2nd, 3rd, 4th, ...と書きます.ゲームなどの順位や,カレンダーの日付で見かけます.
そしてこの「st」「nd」「rd」「th」を,(序数の)接尾辞といい,基数(以下では「もとの数」と呼び,正の整数に限定します)に対し,次のルールで接尾辞が決まります.

  • もとの数の10の位が1のとき,接尾辞は「th」
  • もとの数の1の位が1のとき,接尾辞は「st」
  • もとの数の1の位が2のとき,接尾辞は「nd」
  • もとの数の1の位が3のとき,接尾辞は「rd」
  • いずれでもないとき,接尾辞は「th」

1から数え上げていくと,「もとの数の10の位が1のとき」のもっとも小さい数は10で,11, 12, 13, 14, ..., 19と続きます.それぞれ,序数のスペルは,tenth, eleventh, twelfth, thirteenth, fourteenth, ..., nineteenthとなり,接尾辞はみな「th」です.なお20から23までは,twentieth,twenty-first, twenty-second, twenty-thirdとなり,これらは上記の「もとの数の1の位が1のとき」から始まる4つのルールにより,接尾辞が決まります.
準備が長くなりました.「もとの数」を,変数nに格納させておく(例えば,scanf関数で入力を獲得する)と,数および接尾辞の出力処理は以下のように書くことができます.

if ((n / 10) % 10 == 1) {
  printf("%dth\n", n);
} else if (d == 1) {
  printf("%dst\n", n);
} else if (d == 2) {
  printf("%dnd\n", n);
} else if (d == 3) {
  printf("%drd\n", n);
} else {
  printf("%dth\n", n);
}

ここはelse ifを活用します.というのも5つ書いた,ライブラリ関数printfの呼び出しのうち,条件に合うよう,いずれか必ず1つを,実行する必要があるからです.
上記について,else ifを,単なるifにすると,どうなるでしょうか.次のコードです.

if ((n / 10) % 10 == 1) {
  printf("%dth\n", n);
}
if (d == 1) {
  printf("%dst\n", n);
}
if (d == 2) {
  printf("%dnd\n", n);
} 
if (d == 3) {
  printf("%drd\n", n);
} else {
  printf("%dth\n", n);
}

これでは,「いずれか必ず1つを,実行する」というわけにいきません.例えばnが11のとき,最初の条件式の「(n / 10) % 10 == 1」*1が真となるので「11th」を出力し,その次の条件式の「d == 1」も真となるので,もう一度,「11st」を出力してしまいます*2
「if〜(任意個の)else if〜else〜」は,条件分岐により,その中の処理を必ず1つだけ行うときに書く,と理解しておきましょう.

*1:左辺は「nの10の位の数」になります.実際のところ,nを10で割ることで「10の位の数」が「1の位」に移動し,そのあと,10で割った余りを求めています.カッコを取り除いて「n / 10 % 10 == 1」としても,動作は変わりません.

*2:elseをまったく使うことなく,5つのprintfの呼び出しのうち1つだけを行うようにするには,例えばprintfの呼び出しの直後にreturn文を書いて,関数の処理をそこで終えるというのが考えられます.とはいえ,そのような書き方も「Cらしい」とは言えません.