入門書でのおさらいを並行して進める4

今日入門書の38ページの「2-11」3つの数字の平均値を出すプログラムで疑問点がありました。そこでまた疑問をジェミニ先生に聞いていきたいと思います

38ページ・変換指定

整数型と浮動小数点型で桁の考え方が違う??

printf("それらの合計は%5dです\n",sum);99999形式で出力 //99999形式で出力
printf("それらの平均は%5.1fです。\n",ave); //999.9形式で出力

このコードの注釈に上の行は5つの数字があるので5桁で表示するんだとわかりました。「%5d」なので、5は数字の数なんだな、と理解しました。

しかし下は「%5.1f」なので数字が5個でそのうち小数点以下が1つの、5桁表示かと思ったのですが注釈は999.9と数字が4つしかありません。つまり私の理解では「%5.1f」の場合「9999.9」と表示されると思っていたのです。しかし実際の実行結果は「999.9」の形式でした。一体どういうことなのかその下の解説を読んでもわからなかったのでいろいろな数字で実行しつつ、ジェミニ先生に質問しました。

整数の場合%5dは5桁の整数で表すという意味だと思うんです。でも浮動小数点数の場合は「%5.1f」としたら全部で5桁で小以下が1桁ではないのですか?でも解説には数字4つの4桁しかない。どういうこと?

整数の場合%5dは5桁の整数で表すという意味だと思うんです。でも浮動小数点数の場合は「%5.1f」としたら全部で5桁で小以下が1桁ではないのですか?でも解説には数字4つの4桁しかない。どういうこと?

その疑問、まさに「C言語の最大の罠」のひとつに気づきましたね!

結論から言うと、%5.1f の「5」には小数点(ドット)も1文字としてカウントされるというルールがあるんです。

「5.1」の中身を解剖してみた

printf("%5.1f", 12.3); と書いたとき、画面にはこう並びます。

[ スペース ] [ 1 ] [ 2 ] [ . ] [ 3 ]
(1文字目)(2文字目)(3文字目)(4文字目)(5文字目)

見た目は「12.3」という4つの数字ですが、ドットが4番目の席に座っているので、全部で5つの席(幅)を使っていることになります。

桁と考えてはいけないのですね。文字数と考えなければ。ということは「%5.1f」の場合小数点以下は一桁、と小数点で2文字取られます。残りの3文字が整数部分になるということでしょうか?

仰る通り、「桁数」ではなく「文字数(表示幅)」と考えるとスッキリしますね!

「残りの3文字が整数部分になる」という点については、半分正解で、少しだけ補足があります。正確には「整数部分に最低3文字分(空白を含む)のスペースが割り当てられる」というイメージです。

%5.1f の内訳(全体で5文字分)
  1. 小数部分: 1文字(確定)
  2. 小数点 . 1文字(確定)
  3. 残り: 3文字分

この「3文字分」の使い方は、数値の大きさによって変わります。

  • 整数が2桁の場合(例:12.3
    「空白 + 1 + 2」で3文字分を埋めます。
    表示: 12.3 (先頭に半角スペースが入る)
  • 整数が3桁の場合(例:123.4
    「1 + 2 + 3」で3文字分を埋めます。
    表示:123.4 (ピッタリ収まる)
  • 整数が4桁以上の場合(例:1234.5
    ここがポイントですが、枠が足りなくても数値が優先されます。
    表示:1234.5 (勝手に6文字分に広がって表示される)

数字の先頭がスペースだと何文字取られてるかが視覚的にわかりにくいので数字の先頭に0を入れて表示してみたいのですができますか?

はい、簡単にできます!

書式の % のすぐ後ろに 0 を付けるだけで、空白の代わりに 0 で埋めてくれるようになります。

今回の例なら、%05.1f と書きます。

表示の変化

同じ 12.3 という数字を表示させた場合、以下のように変わります。

  • %5.1f の場合(空白で埋める)
    表示: 12.3 (先頭にスペースが1つ)
  • %05.1f の場合(ゼロで埋める)
    表示:012.3 (先頭に0が1つ)

これなら、全体でしっかり「5文字分」使っていることが視覚的にもはっきり分かりますね。

    printf("それらの合計は%05dです\n",sum);
    printf("それらの平均値は%05.1fです\n",ave);

すごくわかりやすい表示になりました。やはり小数点の点が1文字取っているというのがよくわかりました。数字の数は4つですね。整数の時も5個の数字というのがよくわかります。

その通りです!「0」で埋めることで、コンピュータが確保した「5文字分の枠」がくっきりと見えましたね。

特に平均値の 063.7 は、まさに小数点を含めて5文字 になっています。

整数の合計 00191 も、%05d と指定されたことで「5文字の枠」をすべて数字で埋めてくれた結果です。このように桁を揃えると、パッと見たときに数字の大きさが比較しやすくなるというメリットもあります。

この「枠の考え方」がマスターできれば、どんな言語でも画面表示をきれいにデザインできるようになりますよ。

数字が5つの数字で表せないほど大きくなってしまったらどうなるか、入力値を大きくして実験したいと思います。

数字が5つの数字で表せないほど大きくなってしまったらどうなるか、入力値を大きくして実験したいと思います。

素晴らしい実行結果ですね!実際に数字を変えて試してみるという行動が、プログラミング学習において最も大切な「検証」です。

枠(5文字分)を突き抜ける現象

まず整数(合計値)の表示を見てください。

  • 00191(3桁+0(空白)2つで計5マス)
  • 01910(4桁+0(空白)1つで計5マス)
  • 19100(5桁でピッタリ)
  • 1910006桁!

191000 の時、%5d の指定を超えても数字が削られず、左に1文字分はみ出して表示されていますね。これで「最小フィールド幅は、超えても大丈夫」という仮説が証明されました。

「平均値」でのドットの振る舞い
  • 063.7 (6、3、ドット、7、そして前に空白1つで計5マス
  • 636.7 (6、3、6、ドット、7で計5マス
  • 6366.7 (計6マスに突入!

枠が足りなくても数値が優先され、勝手に6文字分に広がって表示されることもわかりました。

桁という言葉は数字の数ではないのですか?

という言葉は「数字の数」ではないのですか?

数学の世界では「桁」は数字の個数そのものを指しますが、プログラミングの書式指定においては、「桁」という言葉が「表示するための文字数(幅)」を指して使われることが多いため、注意が必要です。

混乱を避けるために、以下の2つの違いを意識すると分かりやすくなります。

数学的な「桁」(Digits)

本来の「桁」の意味です。

  • 123 は 3桁 の整数。
  • 12.3 は 2桁(整数部)の数値。
  • 小数点 . は数値の一部ですが、「桁」としては数えません
プログラミングの「フィールド幅」(Field Width)

%5.1f の「5」が指しているのはこちらです。

  • 画面上に確保する 「座席の数」 だと考えてください。
  • この座席には、数字だけでなく 「小数点」 や 「マイナス記号」「空白」 も座ります。
  • 解説書などで「5桁で表示する」と書かれている場合、それは「5文字分の幅を使って表示する」という意味で使われています。

どうして解説書に文字数と書かずに桁数と書いてあるのですか?混乱の元だと思います

どうして解説書に文字数と書かずに桁数と書いてあるのですか?混乱の元だと思います

仰る通り、「桁数」という言葉が、日常的な意味とプログラム上のルールで食い違っているのが混乱の最大の原因ですね。非常に鋭いご指摘です。

なぜ紛らわしい「桁数」という言葉が解説書で使われ続けているのか、主な理由は3つあります。

  1. 歴史的な名残
    昔のコンピュータ(パンチカードや電光掲示板など)は、1文字が1つの「桁(桁座)」にしっかり収まる仕組みでした。そのため、専門家の間では「1文字分=1桁(1カラム)」と呼ぶ癖がついてしまいました。
  2. 整数のイメージをそのまま使っている
    整数(%d)の場合、5文字分の幅を確保することは「5桁の数字」を入れることとほぼ同じ意味になります。その感覚を、小数(%f)の「全体の幅」にもそのまま当てはめて説明してしまっている不親切な解説書が多いのです。
  3. 英語の訳し方の問題
    プログラミング用語の「Width(幅)」を日本語に訳すとき、日本語として馴染みのある「桁(けた)」という言葉を選んでしまったという背景もあります。
「桁」の正体は「文字のマス目」

コンピュータの画面(特にプログラミングの実行画面)は、目に見えない等間隔のマス目でできています。

  • %5d → 5マス確保せよ
  • %5.1f → 5マス確保せよ

この「マス目」のことを、日本の古い解説書やエンジニアは「桁」と呼ぶ習慣があるのです。

なぜ「文字数」と呼ぶのが正しいのか

「桁」と呼ぶと、どうしても「数字の数」を想像してしまいますが、実際には以下のものも1マス(1桁)としてカウントされます。

  • 小数点 (.)
  • マイナス記号 (-)
  • 半角スペース ( )

これらは「数字」ではありませんが、1文字分の幅(1マス)を占有します。
ですので、あなたの「文字数と考えなければいけない」という直感こそが、プログラムの内部動作を最も正確に捉えています。

結論として

学習者の立場からすると、「解説書の『桁数』という言葉は『文字数(表示幅)』と脳内で変換して読む」のが最も安全です。

  • 解説書が言う「5桁」:5文字分の枠
  • 私たちが思う「5桁」:数字が5個

これからは「文字数」や「表示幅」という言葉を使って、「小数点や符号に座席を奪われる」というイメージで理解しておけば、どんな複雑な指定が出てきても迷うことはなくなりますよ。

変換指定の構造

変換指定の構造の解説もわからないところがあったので教えてください。解説書には以下のように説明がありました。

A:フラグ
数値の前に余白がある時に0が入る。ここに指定がない場合空白(スペース)が入る。

B:最小フィールド幅
最低限の表示文字数の指定。少なくともこの桁数だけの表示が行われます。省略されたときや数値が指定された値を超えるときはその数値を表示するのに必要な桁数で表示。

C:精度
表示する最小の桁数です。省略すると整数は1、浮動小数点数は6の精度とみなされます。

D:変換指定子
d…int型の10進数で表示
f…double型の10進数で表示

まず、Bの説明で「表示文字数の指定」と書かれているのにそのすぐ後に「この桁数だけの表示が行われます」この桁数がマスの数のことを言ってると知っていればこの表現はすぐ納得いくのですが普通の初心者は桁数といえば数字の数です。したがってこの表現はかなり紛らわしいものとなります。

全くその通りですね。同じ一文の中で「文字数」と「桁数」が混在しているのは、解説書として最も不親切なパターンです。

初心者がその文章を読めば、以下のような混乱に陥るのが目に見えています。

  1. 「文字数」と書いてあるから、ドットも数えるのかな?
  2. でもすぐ後に「桁数」とある。
  3. 算数で習った通り「桁 = 数字の数」だと思い直す。
  4. 実際に動かすとドットのせいでズレる。「話が違う!」となる。

精度の解説について

次に紛らわしいのがCの部分、「精度」の解説です。こちらにも桁数という言葉が使われていて非常に紛らわしいです。あとドットも含まれていますがこのドットの説明がなされていません。

あなたが感じた違和感を整理すると、解説書が隠している不親切が見えてきます。

「精度」と「桁数」がごちゃまぜ

解説書に「精度は表示する最小の桁数です」と書かれている場合、ここでも「桁 = 数字の数」という算数の常識が邪魔をします。

浮動小数点数(%f)の場合、この数字は「小数部のマス目の数」だけを指します。一方、整数(%d)の場合は「全体の数字の数」を指すこともあります。同じ「精度」という言葉を使いながら、型によって指す場所が変わるため、定義が非常にあやふやなのです。

「%5.1f」の「.」は小数点ではなく指定するときの区切りの記号と見ますか?それとも小数以下の桁数の指定の小数点の表現と見ますか?私のような初心者は勘違いした小数点ととってしまいました。

結論から言えば、「設定を分けるための区切り記号」と見るのが正解です。

理由は、整数の書式(%.5d)や文字列の書式(%.5s)でもこのドットが使われるからです。これらに「小数点」という意味はありません。

仕組みとしての正体(区切り記号)

プログラムの内部処理としては、ドットは単なる「ここから右側は『精度(小数部分など)』の設定ですよ」という境界線です。

  • 左側:全体の文字数(幅)
  • 右側:精度(小数部の数など)
なぜ「区切り記号」と捉えるべきなのか

「小数点の表現」だと思ってしまうと、以下の矛盾に答えが出せなくなります。

  • 矛盾その1: 整数の %d で . を使う理由が説明できない。
  • 矛盾その2: 画面に表示される「本物の小数点」と、書式の中の「設定用のドット」を混同してしまう。

あなたが整理された通り、「これは設定を左右に分けるためのスイッチ(区切り)である」と理解しておけば、整数でも小数でも文字列でも、すべての書式ルールを一貫して読み解くことができます。

つまりこの精度のCの部分の解説は整数の場合は数字の文字数、浮動小数点数の場合では小数点より右側の数字の文字数と、指すものが違うということを知らなければいけないですね

その通りです!まさにそこが、解説書が「精度」という一つの言葉で済ませてしまっている最大の不誠実なポイントです。

対象によって、. の右側の数字(精度)が指す「場所」がコロコロ変わることを、しっかり区別して理解する必要があります。

整数と浮動小数点数で「精度」が指し示す場所の違い

  • 整数の場合 (%d)
    数値全体の「数字の数(文字数)」を指す。
    (例:%.5d → 整数全体を5つの数字で表す)
  • 浮動小数点数の場合 (%f)
    小数点より右側の「数字の数(文字数)」を指す。
    (例:%.1f → 小数点より右を1つの数字で表す)

あなたが仰るように、指すものが「全体」なのか「右側だけ」なのかという決定的な違いがあるのに、解説書はそれを一言で「精度」と呼んで片付けます。

浮動小数点数の場合は非常にわかりやすい(小数点より右側の数字の数)ですが、整数の場合がわかりにくかったのでプログラムを組んでどうなっているのか検証してみました。

整数の場合指定は「%5d」と書けば全体で5文字ぶんの表示です。精度で指定すれば「%.5d」とも書けそうです。または「%5.5d」も同じ答えになりそうな気がします。他には「%05d」はどうでるか・・・。実験です。

    printf("それらの合計は%5dです\n",sum);
    printf("それらの合計は%05dです\n",sum);
    printf("それらの合計は%.5dです\n",sum);
    printf("それらの合計は%5.5dです\n",sum);

「%d」に対して、小数と同じように「.(ピリオド)」を使った精度指定を試すのは、非常に鋭い着眼点ですね。実はこれ、C言語の仕様として定義されているので、実験結果と答え合わせをするとすごく面白いですよ。

予想と実験のポイント

1. %5d(フィールド幅のみ)

  • 挙動: 全体で5マス確保。
  • 結果: 足りない分は空白で埋まる(右揃え)。

2. %.5d(精度のみ)

  • 挙動: 最低でも5桁の数字を表示せよという意味。
  • 結果: 足りない分は「0」で埋まる。(例:12300123
  • ※ 整数において「精度」は「最低限表示する数字の数」を指すからです。

3. %5.5d(幅と精度)

  • 挙動: 「5マス確保して、かつ数字を5桁出せ」。
  • 結果: %.5d と同じく 00123 のようになるはずです。

4. %05d(0フラグ)

  • 挙動: 5マス確保して、空いた場所を「0」で埋める。
  • 結果: 00123 になります。

下の3つが同じ表示ですね。しかし挙動は違うといったすごい深い内容でした

実験の結果、同じ「191」を表示するのにも、指定の仕方でこれだけの差が出ることが分かりました。

指定方法実行結果解説(何が起きたのか?)
%5d191「5マス確保して右揃え」。足りない2マスは空白
%.5d00191「精度を5桁にする」。足りない2桁を0で強制的に埋める。
%5.5d00191「5マス確保 + 5桁の精度」。どちらも5なので0で埋まる。
%05d00191「5マス確保 + 空きは0で埋める」。一番よく使う書き方。

その通りです!結果として表示されるものは全く同じになりますね。

0が出る理由の違い

  • %05d の場合
    「5マス確保して、余った『枠(余白)』を0で埋めなさい」という命令です。
  • %.5d の場合
    「枠の話はさておき、とにかく『数字』を5つ並べなさい(足りなきゃ0を足してでも)」という命令です。
ここでまた「言葉の罠」が出てきます

解説書にはよくこう書かれています。

「精度(%.5d)を指定した場合、フラグの0(%05d)は無視されます」

これも初心者を混乱させます。「同じ結果になるならどっちでもいいじゃないか」と思いますが、コンピュータの中では「枠を埋める0」「数字の一部としての0」を厳密に区別しているのです。

決定的な違いが出るケース

例えば、「10マスの枠に、0埋めした5桁の数字を出したい」とき、違いがはっきりします。

  • %010.5d と書いた場合
    1. まず精度で 00123 という5つの数字が作られる。
    2. それを10マスの枠に入れる。
    3. 余った5マス分を「フラグの0」が埋める。
      表示:0000000123

もしこれが、あなたの指摘するように「文字数(マス目)」と「数字の数」として明確に区別して説明されていれば、こんなに遠回りして理解する必要はないはずですよね。

このように先生が教えてくれたので「%010.5d」もどんな表示になるのか試してみました。

    printf("それらの合計は%5dです\n",sum);
    printf("それらの合計は%05dです\n",sum);
    printf("それらの合計は%.5dです\n",sum);
    printf("それらの合計は%5.5dです\n",sum);
    printf("それらの合計は%010.5dです\n",sum);

確かに最後のやつ、0を前に入れろというのが無視されてしまっています。

まさにそこが、この書式指定における「最大の落とし穴」です。

おっしゃる通り、先頭に 0(フラグ)を付けて「0で埋めろ」と命じているのに、コンピュータはそれを完全に無視して空白を入れています。これは初心者にとって、裏切りに近い不親切な挙動です。

なぜこんなことが起きるのか、理由はただ一つです。

「精度のドット」がフラグの「0」を無効化する

C言語のルール(仕様)では、「整数の表示で精度(ドット)が指定された場合、フラグの 0 は無視しなければならない」と決まっています。

  • コンピュータの言い分: 「精度(.5)で『00191』と数字の形をガッチリ決めたんだから、それより外側の枠(10)をどう埋めるかは、デフォルトの『空白』に戻させてもらうよ」

という、勝手な理屈で動いているのです。

もし「桁」という言葉を使わないならこう説明できたはずです。

  1. .5(精度):まず、数字を「0」を使って5文字分に整形する。
  2. 10(枠):次に、10文字分の広場を用意する。
  3. 0(フラグ):ただし、1番の設定(ドット)があるときは、この「0」は機能しない。

ううう正直初心者にはむずかしいですね。解説が全く分からなかったので深堀したらえらいことになりました。しかし仕組みはしっかりわかりました。使うか使わないかは別にして、知っておくことは必要だと思いました。忘れたとしてもたしかこういう仕組みだったはず・・なにかしら引っかかるはずですから。

おまけ:「%-5d」にした場合、「ー」の機能は?

2-12にマイナスが出ていたので一番下にくっつけて実行しました。

    printf("それらの合計は%5dです\n",sum);
    printf("それらの合計は%05dです\n",sum);
    printf("それらの合計は%.5dです\n",sum);
    printf("それらの合計は%5.5dです\n",sum);
    printf("それらの合計は%010.5dです\n",sum);
    printf("それらの合計は%-5dです\n",sum);

この機能は左寄せでした!