C 04 — Conversión numérica y bases
ft_atoi) y la representación de números en distintas bases. En base N, cada dígito vale su posición multiplicada por N elevado a su índice. Binario=base 2, Octal=base 8, Decimal=base 10, Hex=base 16.
EX 03 ft_atoi — CLÁSICO DE EXAMEN ★★★☆ Difícil ▼
Convierte un string en int. Maneja espacios al inicio, signos + y - múltiples (los negativos cambian el signo según paridad), y dígitos hasta encontrar un no-dígito.
Ejemplo: " ---+--+1234ab567" → -1234 (3 negativos = signo negativo, se para en 'a').
- Fase 1 — Espacios: Salta todos los caracteres que son espacio:
' ','\t','\n','\r','\f','\v'(los 6 que define isspace). - Fase 2 — Signos: Lee
+y-. Cada-invierte el signo. Usa una variablesign = 1y multiplica por-1cada vez que encuentras un-. - Fase 3 — Dígitos: Mientras el char es dígito (
'0'–'9'), construye el número:result = result * 10 + (str[i] - '0'). - Devuelve
result * sign.
int ft_atoi(char *str)
{
int i;
int sign;
int result;
i = 0;
sign = 1;
result = 0;
while (str[i] == ' ' || (str[i] >= '\t' && str[i] <= '\r'))
i++;
while (str[i] == '+' || str[i] == '-')
{
if (str[i] == '-')
sign = sign * -1;
i++;
}
while (str[i] >= '0' && str[i] <= '9')
{
result = result * 10 + (str[i] - '0');
i++;
}
return (result * sign);
}
str[i] >= '\t' && str[i] <= '\r' captura \t \n \v \f \r de una vez porque son ASCII 9–13 consecutivos.
str[i] - '0' convierte el carácter dígito en su valor numérico: '5' - '0' = 53 - 48 = 5.
EX 04 ft_putnbr_base — MUY FRECUENTE EN EXAMEN ★★★☆ Difícil ▼
Muestra nbr en la base dada. La base es un string donde cada carácter es un símbolo. Si la base es inválida (vacía, tamaño 1, contiene +, -, o caracteres repetidos), no muestra nada.
base[nbr % 16] da el dígito hexadecimal. Recursivamente imprime nbr / base_len primero, luego el dígito actual.
- Calcula base_len: recorre la base hasta '\0'.
- Valida la base: si len < 2, o contiene '+'/'-', o tiene duplicados → return.
- Gestiona negativos: si nbr < 0 imprime '-' y niega nbr (con cuidado al INT_MIN).
- Si
nbr >= base_len, llama recursivamente connbr / base_len. - Imprime
base[nbr % base_len]— el dígito actual.
#include <unistd.h>
static int ft_base_len(char *base)
{
int i;
int j;
i = 0;
while (base[i])
{
if (base[i] == '+' || base[i] == '-')
return (0);
j = i + 1;
while (base[j])
{
if (base[i] == base[j])
return (0);
j++;
}
i++;
}
return (i);
}
void ft_putnbr_base(int nbr, char *base)
{
int len;
char c;
len = ft_base_len(base);
if (len < 2)
return ;
if (nbr == -2147483648)
{
ft_putnbr_base(-214748364, base);
c = base[8 % len];
write(1, &c, 1);
return ;
}
if (nbr < 0)
{
write(1, "-", 1);
nbr = -nbr;
}
if (nbr >= len)
ft_putnbr_base(nbr / len, base);
c = base[nbr % len];
write(1, &c, 1);
}
-2147483648 / base da -214748364 y el dígito restante es 8 (en decimal). Se adapta al índice de la base.
EX 05 ft_atoi_base ★★★★ Muy difícil ▼
Como ft_atoi pero convierte desde una base específica. Mismo comportamiento de signos y espacios. Si la base es inválida devuelve 0. No hay espacios en la base (a diferencia de ft_putnbr_base, aquí los espacios en la base también son error).
- Valida la base igual que en ft_putnbr_base (más: no puede contener espacios).
- Salta espacios al inicio del string.
- Lee signos
+y-acumulando el signo. - Para cada carácter de str, busca su índice en la base. Ese índice es su valor.
- Construye el número:
result = result * base_len + indice_en_base.
static int ft_find_in_base(char c, char *base)
{
int i;
i = 0;
while (base[i])
{
if (base[i] == c)
return (i);
i++;
}
return (-1); // no encontrado
}
int ft_atoi_base(char *str, char *base)
{
int i;
int len;
int sign;
int result;
int val;
len = ft_base_len(base); // misma función de antes
if (len < 2)
return (0);
i = 0;
sign = 1;
result = 0;
while (str[i] == ' ' || (str[i] >= '\t' && str[i] <= '\r'))
i++;
while (str[i] == '+' || str[i] == '-')
{
if (str[i] == '-')
sign *= -1;
i++;
}
val = ft_find_in_base(str[i], base);
while (val != -1)
{
result = result * len + val;
i++;
val = ft_find_in_base(str[i], base);
}
return (result * sign);
}
C 05 — Recursión y matemáticas
// Patrón general de función recursiva:
int funcion_recursiva(int n)
{
if (n == CASO_BASE) // ← condición de parada
return (VALOR_BASE);
return (funcion_recursiva(n - 1) * n); // ← llamada recursiva
}
EX 00 ft_iterative_factorial ★★☆☆ Medio ▼
Factorial iterativo: n! = 1×2×3×...×n. Si nb < 0 devuelve 0. 0! = 1.
int ft_iterative_factorial(int nb)
{
int result;
if (nb < 0)
return (0);
result = 1;
while (nb > 1)
{
result = result * nb;
nb--;
}
return (result);
}
result = 1 porque 1 es el neutro de la multiplicación. El loop empieza desde nb y va bajando hasta 2. Con nb=0 o nb=1 el while no se ejecuta y devuelve 1, que es correcto (0! = 1! = 1).
EX 01 ft_recursive_factorial ★★☆☆ Medio ▼
Factorial recursivo. Misma lógica pero con llamadas a sí mismo. n! = n × (n-1)!
int ft_recursive_factorial(int nb)
{
if (nb < 0)
return (0);
if (nb <= 1)
return (1); // caso base: 0! = 1! = 1
return (nb * ft_recursive_factorial(nb - 1));
}
// 5! → 5 × 4! → 5 × 4 × 3! → ... → 5×4×3×2×1 = 120
EX 02 / 03 ft_iterative_power / ft_recursive_power ★★☆☆ Medio ▼
Calcula nbpower. Si power < 0 devuelve 0. 00 = 1 (decisión del enunciado).
int ft_iterative_power(int nb, int power)
{
int result;
if (power < 0)
return (0);
result = 1;
while (power > 0)
{
result = result * nb;
power--;
}
return (result);
}
int ft_recursive_power(int nb, int power)
{
if (power < 0)
return (0);
if (power == 0)
return (1);
return (nb * ft_recursive_power(
nb, power - 1));
}
EX 04 ft_fibonacci — CLÁSICO DE EXAMEN ★★★☆ Difícil ▼
Devuelve el elemento en la posición index de la secuencia de Fibonacci: 0, 1, 1, 2, 3, 5, 8, 13, 21... Si index < 0 devuelve -1. Debe ser recursiva.
int ft_fibonacci(int index)
{
if (index < 0)
return (-1);
if (index == 0)
return (0); // fib(0) = 0
if (index == 1)
return (1); // fib(1) = 1
return (ft_fibonacci(index - 1) + ft_fibonacci(index - 2));
}
// fib(5) → fib(4) + fib(3) → ... → 3 + 2 = 5 ✓
EX 05 ft_sqrt ★★☆☆ Medio ▼
Devuelve la raíz cuadrada entera de nb si es exacta, 0 si no. Ej: sqrt(25)=5, sqrt(26)=0.
int ft_sqrt(int nb)
{
int i;
if (nb < 0)
return (0);
if (nb == 0)
return (0);
i = 1;
while (i * i <= nb)
{
if (i * i == nb)
return (i);
i++;
}
return (0);
}
i * i <= nb para antes de que i supere la raíz real. Si ningún i exactamente satisface i*i == nb, devuelves 0.
EX 06 ft_is_prime ★★☆☆ Medio ▼
Devuelve 1 si nb es primo, 0 si no. 0 y 1 no son primos. Un número es primo si solo es divisible entre 1 y él mismo.
int ft_is_prime(int nb)
{
int i;
if (nb <= 1)
return (0);
i = 2;
while (i * i <= nb)
{
if (nb % i == 0)
return (0); // tiene divisor → no es primo
i++;
}
return (1);
}
EX 07 ft_find_next_prime ★★☆☆ Medio ▼
Devuelve el primer número primo ≥ nb. Si nb ya es primo, devuelve nb.
int ft_find_next_prime(int nb)
{
if (nb <= 2)
return (2);
while (!ft_is_prime(nb))
nb++;
return (nb);
}
// Reutiliza ft_is_prime — la clave de C05
ft_is_prime en el mismo archivo o declarada como static arriba.
C 06 — argc y argv
main. argc es el número de argumentos (incluido el nombre del programa). argv es un array de strings: argv[0] es el nombre del programa, argv[1] es el primer argumento, etc.
Ejemplo: ./programa hola mundo
int main(int argc, char **argv). Puedes usar ft_putstr que ya escribiste en C01/C04.
EX 00 ft_print_program_name ★☆☆☆ Básico ▼
Programa que imprime el nombre con el que fue ejecutado (argv[0]) seguido de un salto de línea.
#include <unistd.h>
static void ft_putstr(char *str)
{
int i;
i = 0;
while (str[i])
{
write(1, &str[i], 1);
i++;
}
}
int main(int argc, char **argv)
{
(void)argc; // evita warning de variable no usada
ft_putstr(argv[0]);
write(1, "\n", 1);
return (0);
}
(void)argc; silencia el warning de la Norma por variable sin usar. Es la forma idiomática de C para decir "este parámetro es intencionalmente ignorado".
EX 01 ft_print_params ★☆☆☆ Básico ▼
Imprime todos los argumentos excepto argv[0], uno por línea, en el mismo orden que se recibieron.
int main(int argc, char **argv)
{
int i;
i = 1; // empieza en 1 para saltar argv[0]
while (i < argc)
{
ft_putstr(argv[i]);
write(1, "\n", 1);
i++;
}
return (0);
}
EX 02 ft_rev_params ★★☆☆ Medio ▼
Igual que el anterior pero en orden inverso. Si se ejecuta con test1 test2 test3, imprime test3, test2, test1.
int main(int argc, char **argv)
{
int i;
i = argc - 1; // último argumento
while (i >= 1) // hasta 1 (saltamos argv[0])
{
ft_putstr(argv[i]);
write(1, "\n", 1);
i--;
}
return (0);
}
EX 03 ft_sort_params — CLÁSICO DE EXAMEN ★★★☆ Difícil ▼
Imprime todos los argumentos (excepto argv[0]) ordenados según el orden ASCII, uno por línea.
- Necesitas comparar strings con tu
ft_strcmp. - Usa bubble sort: recorre el array, si
argv[i] > argv[i+1](en orden ASCII) los intercambias. - Para comparar strings:
ft_strcmp(argv[i], argv[i+1]) > 0significa que argv[i] viene después en ASCII. - El intercambio es de punteros (
char *), no de strings completos. Solo intercambias las direcciones.
static int ft_strcmp(char *s1, char *s2)
{
int i;
i = 0;
while (s1[i] == s2[i] && s1[i])
i++;
return ((unsigned char)s1[i] - (unsigned char)s2[i]);
}
int main(int argc, char **argv)
{
int i;
char *tmp;
i = 1;
while (i < argc - 1)
{
if (ft_strcmp(argv[i], argv[i + 1]) > 0)
{
tmp = argv[i]; // intercambio de punteros
argv[i] = argv[i + 1];
argv[i + 1] = tmp;
i = 1; // reinicia para re-verificar
}
else
i++;
}
i = 1;
while (i < argc)
{
ft_putstr(argv[i]);
write(1, "\n", 1);
i++;
}
return (0);
}
char *tmp = argv[i]; argv[i] = argv[i+1]; argv[i+1] = tmp; — intercambiamos punteros (direcciones), no copiamos strings. Más eficiente y más simple.
i y tmp, más argc y argv como parámetros. Los parámetros no cuentan como variables declaradas.
F1 en vim)2.
cc -Wall -Wextra -Werror — cero warnings3. Prohibido: for · switch · goto · ternario · do...while
4. En C06: los programas llevan
int main(int argc, char **argv)5. Usa
(void)argc si no usas el parámetro, para evitar warnings6. El intercambio en ft_sort_params es de punteros, no de strings