En esta página

Ejercicio 05: ft_print_comb

Muestra todas las combinaciones únicas de tres dígitos distintos, con los dígitos de cada combinación en orden ascendente y las combinaciones también ordenadas de forma ascendente.

DatoValor
Carpetaex05/
Archivoft_print_comb.c
Prototipovoid ft_print_comb(void);
Funciones autorizadassolo write

Hecho con amor para Laura, por Bogdan.

El archivo

#include <unistd.h>

/*
** Copia local de ft_putchar: el enunciado solo permite entregar este archivo.
** Escribe un unico caracter en la salida estandar.
*/
static void put_char(char c)
{
    write(1, &c, 1);
}

/*
** Imprime una combinacion. El separador va delante de todas menos la primera,
** para que la salida no termine en ", ".
*/
static void print_combination(char a, char b, char c, int first)
{
    if (!first)
    {
        put_char(',');
        put_char(' ');
    }
    put_char(a);
    put_char(b);
    put_char(c);
}

/*
** Tres bucles anidados, uno por digito, con cada digito por delante del
** anterior. Asi no se repite ninguna combinacion y salen en orden.
** La 'a' no pasa de '7' porque detras hacen falta dos digitos mas.
*/
void    ft_print_comb(void)
{
    char    a;
    char    b;
    char    c;
    int     first;

    first = 1;
    a = '0';
    while (a <= '7')
    {
        b = a + 1;
        while (b <= '8')
        {
            c = b + 1;
            while (c <= '9')
            {
                print_combination(a, b, c, first);
                first = 0;
                c++;
            }
            b++;
        }
        a++;
    }
    put_char('\n');
}

Línea por línea

#include <unistd.h>

Declara write, la única función de librería permitida. La explicación está en el ejercicio 00.

static void put_char(char c)

Copia privada de ft_putchar. static la encierra en este archivo, para que no choque con la de otros ejercicios si compilas varias juntas.

static void print_combination(char a, char b, char c, int first)

Esta función imprime una combinación y decide si lleva separador delante. Recibe cuatro datos:

ParámetroQué es
a, b, clos tres dígitos, ya en orden
first1 si es la primera combinación, 0 si no

Es static porque es un ayudante interno: nadie de fuera del archivo la usa.

if (!first)

! es el operador de negación: !first vale verdadero cuando first es 0. La idea se lee al revés de lo habitual: si no es la primera, escribe el separador.

Así la salida empieza directamente en 012 y no termina en ", ". Poner el separador detrás de cada combinación es el error clásico de este ejercicio.

put_char(','); y put_char(' ');

El separador son dos caracteres: una coma y un espacio. No existe un carácter «coma y espacio»; hay que escribir los dos.

put_char(a); put_char(b); put_char(c);

Los tres dígitos seguidos. a, b y c ya son caracteres, no números, así que no hay que convertirlos.

void ft_print_comb(void)

La función pública del ejercicio. No devuelve nada y no recibe parámetros.

char a; char b; char c;

Los tres dígitos de la combinación actual. Se declaran arriba, como pide el estilo de la piscina, y se inicializan dentro de los bucles.

int first;

La bandera que recuerda si ya se imprimió algo. Es int y no char porque su valor es 1 o 0, y así se lee como un booleano.

first = 1;

Antes de la primera combinación, no se ha impreso nada: first vale 1.

a = '0'; y while (a <= '7')

El primer dígito recorre de '0' a '7'. No llega a '8' ni a '9' porque detrás hacen falta dos dígitos mayores: si a fuera '8', no habría forma de completar la terna.

b = a + 1; y while (b <= '8')

b arranca uno por encima de a. Eso es lo que garantiza que no se repita ningún dígito: si a vale '3', b empieza en '4'. Su tope es '8' porque detrás queda c.

c = b + 1; y while (c <= '9')

c arranca uno por encima de b y llega hasta '9', el último dígito disponible.

Imprime la terna con su separador si toca. Los tres dígitos se pasan por valor: la función recibe copias y no puede cambiarlos.

first = 0;

Después de la primera combinación, ya no es la primera. Esta línea está dentro del bucle de c, así que se ejecuta en cada terna.

c++; b++; a++;

Cada bucle avanza su variable. Sin estos incrementos el programa no termina nunca: es el error más caro de este ejercicio porque hay tres bucles y basta con olvidar uno.

put_char('\n');

El salto de línea final va después del último while, no dentro. El enunciado muestra la salida con cat -e y el $ final indica que hay un salto.

Por qué no hay ni un if de comparación

Todo el orden sale de la estructura de los bucles:

Regla del enunciadoCómo se cumple
dígitos distintosb empieza en a + 1 y c en b + 1
dígitos ascendenteslos bucles solo generan a < b < c
combinaciones ascendentesrecorrido lexicográfico de a, luego b, luego c
sin repetir combinacionescada terna se genera exactamente una vez

987 no aparece porque los bucles nunca generan un orden descendente. 999 no aparece porque b y c siempre son mayores que el anterior. No hace falta comprobarlo: la estructura ya lo impide.

Salida esperada

El principio y el final. Los puntos suspensivos son la abreviatura del enunciado, no salida real:

012, 013, 014, 015, 016, 017, 018, 019, 023, ..., 789

Salen 120 combinaciones: las formas de elegir 3 dígitos entre 10, que es 10 × 9 × 8 / (3 × 2 × 1).

Casos límite

DetalleDecisión
Separador finalno se imprime: va delante, no detrás
Salto de línea finalsí, porque el enunciado lo muestra con cat -e
Repeticionesimposibles por el orden de los bucles
Tope de a'7', no '9': hay que dejar sitio a b y c

Errores típicos

Mensaje o síntomaCausaSolución
termina en , separador después de cada ternaponlo delante con first
salen 011, 022…b empieza en '0'b = a + 1
salen ternas desordenadasc no depende de bc = b + 1
se corta en 789 sin saltofalta put_char('\n')añádelo al final
no terminafalta algún ++revisa los tres bucles

Comprobarlo

cat > /tmp/main.c <<'EOF'
void    ft_print_comb(void);

int main(void)
{
    ft_print_comb();
    return (0);
}
EOF
cc -Wall -Wextra -Werror ex05/ft_print_comb.c /tmp/main.c -o /tmp/ex05
/tmp/ex05 > /tmp/salida.txt
wc -c /tmp/salida.txt

Compara contra la salida esperada con cmp, que no imprime nada cuando los dos archivos son idénticos:

cmp /tmp/salida.txt /tmp/esperado.txt

Descargar