HOWTO · C

Alinear columnas en la función printf en C

Este artículo presenta cómo alinear columnas en la función printf en C

En esta página

Usa un ancho de campo de printf para alinear columnas en C. %10d alinea un entero a la derecha en un campo de al menos 10 caracteres; %*d toma ese ancho de un argumento y %0*d rellena el entero con ceros iniciales. Usa %-*s o la marca - para alinear texto a la izquierda en una tabla.

Usa un ancho de campo para alinear la salida en C

El ancho de campo establece el número mínimo de caracteres que se usan para un valor. Para un entero, %10d lo alinea a la derecha y añade espacios a la izquierda cuando ocupa menos de 10 caracteres. Si el valor es más ancho, se imprime completo: el ancho no lo trunca. Esto resulta útil cuando quieres que los últimos caracteres de una columna queden alineados; los valores más cortos empiezan más a la derecha porque la conversión se alinea a la derecha.

Este ejemplo completo muestra los valores alineados a la derecha junto a un separador visible:

#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

La primera conversión reserva un ancho mínimo de 10; la segunda usa el ancho natural del valor. El carácter | permite ver el límite del campo. En general, el número de un formato como %10d indica el ancho mínimo total del campo, no la cantidad de espacios que se deben añadir.

Usa %*d para un ancho de campo dinámico

Usa %*d cuando el ancho del campo solo se conoce mientras se ejecuta el programa. Cada * de una conversión consume un argumento int justo antes del valor correspondiente. Por ejemplo, en printf("%*d", width, value), width proporciona el ancho del campo y value proporciona el entero.

Este ejemplo completo establece el ancho durante la ejecución y lo pasa justo antes de cada valor entero:

#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

La primera conversión usa el valor de width como ancho mínimo del campo, por lo que los enteros más cortos reciben espacios iniciales y los valores más anchos se mantienen completos. La segunda conversión imprime el mismo entero con su ancho natural.

La marca - alinea el valor a la izquierda. Puedes combinarla con un ancho dinámico como %-*d; el argumento del ancho sigue antes del argumento del valor. Por ejemplo, printf("%*d | %-*d\n", width, value, width, value) usa width antes de cada entero correspondiente. El primer campo se alinea a la derecha de forma predeterminada y el segundo, a la izquierda. Pasa un ancho distinto antes de un valor si la disposición cambia entre filas.

Combina anchos de campo para alinear columnas de una tabla

En una tabla con distintos tipos de datos, asigna a los campos de texto y de números anchos que se ajusten a las columnas previstas. La marca - alinea las etiquetas a la izquierda, mientras que las conversiones de enteros sin esa marca alinean los números a la derecha. Un separador | distingue las columnas. En %*.*d, el primer * consume el ancho, el segundo consume la precisión y el argumento final es el valor entero. La precisión de un entero establece un número mínimo de dígitos y añade ceros iniciales cuando hace falta.

Este ejemplo completo de tabla usa columnas de ancho fijo para los encabezados y las filas de muestra. Las etiquetas visibles permanecen en inglés porque los bloques de código y de salida se conservan sin cambios:

#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

Aquí, las columnas del número y de la descripción se alinean a la izquierda para que sea fácil recorrer las filas; quita - de una conversión de entero para alinear ese número a la derecha. Cada ancho o precisión indicado con * debe tener un argumento int correspondiente y en el mismo orden. El ancho que muestra el terminal puede variar con texto que contenga caracteres multibyte o de ancho completo, por lo que estos ejemplos orientados a bytes usan texto ASCII común.

Usa %0*d para rellenar enteros con ceros

Usa %0*d cuando quieras que un entero tenga un ancho mínimo completado con ceros iniciales. El * consume el argumento del ancho antes del entero. A diferencia del relleno con espacios de %*d, el relleno con ceros mantiene los identificadores numéricos y los recuentos con una cantidad uniforme de dígitos.

Este ejemplo completo imprime dos enteros con un ancho mínimo de cinco dígitos:

#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

El ancho es mínimo, así que un valor con más dígitos que el ancho elegido se imprime completo. En una tabla, aplica el mismo ancho numérico a cada fila y usa campos con relleno de espacios para los encabezados o el texto.

Conclusión

Elige %10d u otro ancho de campo fijo cuando la disposición sea conocida. Usa %*d cuando el ancho provenga de una variable y añade - cuando quieras alinear un campo a la izquierda. Usa %0*d para identificadores numéricos o recuentos que necesiten ceros iniciales. Estas opciones de formato facilitan recorrer la salida de consola con texto ASCII común, aunque el ancho de visualización del terminal puede afectar la alineación de otros textos.