HOWTO · C

C 言語で printf 関数で列を揃える

この記事では、C 言語の printf 関数で列を揃える方法を紹介します。

このページの内容

C言語では、printfのフィールド幅を使って列を揃えられます。%10dは整数を幅10文字以上のフィールド内で右寄せし、%*dは幅を引数から受け取ります。%0*dは整数の先頭をゼロで埋めます。表のテキストを左寄せするには、%-*sまたは-フラグを使います。

Cでフィールド幅を使って出力を揃える

フィールド幅は、値の表示に使う文字数の最小値を指定します。整数の場合、%10dは値を右寄せし、10文字に満たなければ左側を空白で埋めます。値が幅を超える場合はそのまま全部表示されるため、幅によって切り詰められることはありません。列の末尾を揃えたいときに便利です。右寄せなので、短い値ほど右側に寄って表示されます。

次の完全な例では、区切り文字の横に値を右寄せして表示します。

#include <stdio.h>

int main(void) {
  int values[] = {11011, 111, 11};

  for (int i = 0; i < 3; ++i) {
    printf("%10d | %d\n", values[i], values[i]);
  }

  return 0;
}
     11011 | 11011
       111 | 111
        11 | 11

最初の変換指定は最小幅10を確保し、2番目は値に応じた幅で表示します。|はフィールドの境界を見やすくします。一般に、%10dのような書式に含まれる数値はフィールド幅の最小値であり、追加する空白の個数ではありません。

動的なフィールド幅に%*dを使う

プログラムの実行時までフィールド幅が決まらない場合は、%*dを使います。変換指定内の各*は、その値の直前に対応するint引数を1つ受け取ります。たとえば、printf("%*d", width, value)では、widthがフィールド幅を指定し、valueが整数を指定します。

次の完全な例では、実行時に幅を設定し、各整数値の直前にその幅を渡します。

#include <stdio.h>

int main(void) {
  int width = 10;
  int values[] = {11011, 111, 11};

  for (int i = 0; i < 3; ++i) {
    printf("%*d | %d\n", width, values[i], values[i]);
  }

  return 0;
}
     11011 | 11011
       111 | 111
        11 | 11

最初の変換指定では、widthの値がフィールド幅の最小値になります。そのため、幅より短い整数の左側には空白が入り、幅を超える値もそのまま表示されます。2番目の変換指定は、同じ整数を自然な幅で表示します。

-フラグを付けると値を左寄せできます。動的な幅と組み合わせるには%-*dとします。この場合も、幅の引数は値の引数より前に置きます。たとえば、printf("%*d | %-*d\n", width, value, width, value)では、対応する各整数の前にwidthを渡します。最初のフィールドは既定で右寄せ、2番目は左寄せです。行ごとに配置を変える場合は、値の直前に異なる幅を渡してください。

フィールド幅を組み合わせて表の列を揃える

文字列と数値が混在する表では、各フィールドに列の内容に合った幅を指定します。-フラグを付けるとラベルが左寄せになり、付けない整数変換は右寄せになります。|で列を区切れます。%*.*dでは、最初の*が幅を、2番目の*が精度を受け取り、最後の引数が整数値になります。整数の精度は桁数の最小値を指定し、必要に応じて先頭にゼロを加えます。

次の完全な表の例では、見出しとサンプル行に固定幅の列を使っています。コードと出力のブロックは変更せず保持しているため、表示される表のラベルは英語のままです。

#include <stdio.h>

int main(void) {
  int width = 12;

  printf("%-*s | %-*s | %*s\n", width, "Number", width,
         "Description", width, "Value");
  printf("%-*d | %-*s | %*.*d\n", width, 123, width, "First",
         width, 4, 4567);
  printf("%-*d | %-*s | %*.*d\n", width, 456, width, "Second",
         width, 4, 789);

  return 0;
}
Number       | Description  |        Value
123          | First        |         4567
456          | Second       |         0789

ここでは、行を読み取りやすくするため、数値列と説明列を左寄せしています。整数変換から-を外すと、その数値を右寄せできます。*で幅や精度を指定するたびに、同じ順序で対応するint引数が必要です。マルチバイト文字や幅の広い文字を含むテキストでは、端末上の表示幅が異なることがあります。そのため、ここでは通常のASCIIテキストを使った、バイト単位の例を示しています。

ゼロ埋めした整数に%0*dを使う

整数を先頭のゼロで埋め、幅の最小値を指定するには%0*dを使います。*は整数より前にある幅の引数を受け取ります。%*dによる空白埋めとは異なり、ゼロ埋めを使うと識別子や件数の桁数を揃えられます。

次の完全な例では、2つの整数を最小幅5桁で表示します。

#include <stdio.h>

int main(void) {
  int width = 5;

  printf("%0*d\n", width, 123);
  printf("%0*d\n", width, 7);

  return 0;
}
00123
00007

幅は最小値なので、桁数が指定した幅を超える値もすべて表示されます。表では、各行の数値に同じ幅を指定してください。見出しやテキストには空白で埋めるフィールドを使います。

まとめ

レイアウトが決まっている場合は、%10dなどの固定フィールド幅を選びます。幅を変数から受け取る場合は%*dを使い、フィールドを左寄せするには-を付けます。先頭にゼロが必要な識別子や件数には%0*dが適しています。こうした書式を使うと、通常のASCII文字によるコンソール出力を読み取りやすくできます。ただし、その他のテキストでは端末上の表示幅によって列の揃い方が変わることがあります。