I had to create my own version of the printf function in C. This project helped me understand how the printf function works and how to handle different format specifiers like %d for integers, %s for strings, and %f for floating-point numbers. I learned about variadic functions, string manipulation, and formatting rules.
A variadic function is a function that can accept a variable number of arguments.
Procedure to use variadic functions in C:
- Include the
<stdarg.h>
header file, which provides the necessary macros and types for working with variadic functions. - Define your variadic function by specifying the variable argument list using an ellipsis (
...
) as the last parameter. - Inside the function, declare a
va_list
variable to hold the variable arguments. - Use the
va_start
macro to initialize theva_list
variable, passing it the last named parameter of the function (before the ellipsis). - Access the variable arguments using the
va_arg
macro, specifying theva_list
variable and the type of the argument you expect. - Process the variable arguments as needed.
- Use the
va_end
macro to clean up theva_list
variable before returning from the function.
Example:
void print_numbers(int fixed_int, double fixed_double, int count, ...)
{
printf("Fixed int: %d\n", fixed_int);
printf("Fixed double: %lf\n", fixed_double);
va_list args;
va_start(args, count);
for (int i = 0; i < count; i++) {
int num = va_arg(args, int);
printf("%d ", num);
}
va_end(args);
printf("\n");
}
int main()
{
print_numbers(3, 10, 2, 30, 40); // Output: 30 40
return 0;
}
Is a type defined in <stdarg.h>
. It is a special type that holds the information needed to access the variable arguments in a variadic function. You declare variables of type va_list
to work with the variable argument list.
Is a macro that initializes a va_list
variable for accessing the variable arguments. It takes two arguments: the va_list
variable and the last named parameter of the function (before the ellipsis). This macro must be called before accessing any variable arguments.
Is a macro used to retrieve the next argument from the variable argument list. It takes two arguments: the va_list
variable and the type of the argument you expect to retrieve. The macro returns the value of the argument and advances the va_list
variable to the next argument.
Is a macro that performs the necessary cleanup after using the variable arguments. It takes one argument: the va_list
variable. It must be called before the function returns to release any resources associated with the variable arguments.
%d
or%i
: Prints an integer in signed decimal format.%u
: Prints an integer in unsigned decimal format.%o
: Prints an integer in octal format.%x
or%X
: Prints an integer in hexadecimal format (lowercase or uppercase).%f
or%F
: Prints a floating-point number in decimal notation.%e
or%E
: Prints a floating-point number in scientific notation.%g
or%G
: Prints a floating-point number in either decimal or scientific notation, depending on the value and precision.%c
: Prints a single character.%s
: Prints a null-terminated string of characters.%%
: Prints a literal '%' character.%p
: Prints a pointer address in hexadecimal format.%n
: Writes the number of characters printed so far into an integer variable passed as an argument.
#include <stdarg.h> // For va_lis, va_start, va_arg, va_copy, va_end
#include <unistd.h> // For malloc, free, write
void put_str(char *str, int *len)
{
if (!str)
str = "(null)";
while (*str)
*len += write(1, str++, 1);
}
void put_digit(long long int nbr, int base, int *len)
{
char *hexa;
hexa = "0123456789abcdef";
if (nbr < 0)
{
nbr *= -1;
*len += write(1, "-", 1);
}
if (nbr >= base)
put_digit((nbr / base), base, len);
*len += write(1, &hexa[nbr % base], 1);
}
int ft_printf(const char *format, ...)
{
int len;
va_list agrs;
len = 0;
va_start(agrs, format);
while (*format)
{
if (*format == '%' && *(format + 1))
{
format++;
if (*format == "s")
put_str(va_arg(agrs, char *), &len);
else if (*format == "d")
put_digit(va_arg(agrs, int), 10, &len);
else if (*format == "x")
put_digit(va_arg(agrs, unsigned int), 16, &len);
}
else
len += write(1, format, 1);
format++;
}
return (va_end(agrs), len);
}