This project has been created as part of the 42 curriculum by someyer
Description
This project is about my implementation of printf function from C standard library. This function accepts a format C-string argument and a variable number of value arguments that the function serializes per the format string.
Here is the function prototype according to the project guidelines:
int ft_printf(const char *, ...);
Requirements
- I shouldn’t implement the buffer management of the original printf()
- Function has to handle the following conversions: cpsdiuxX%
- Function will be compared against the original printf().
- I must use the command
arto create my library. Using libtool command is forbidden. - libftprintf.a has to be created at the root of my repository.
- My header file must be named ft_printf.h and must contain the prototype of my ft_printf() function.

Conversions
%cPrints a single character.%sPrints a string.%pThevoid *pointer argument has to be printed in hexadecimal format.%dPrints a decimal (base 10) number.%iPrints an integer in base 10.%uPrints an unsigned decimal (base 10) number.%xPrints a number in hexadecimal (base 16) lowercase format.%XPrints a number in hexadecimal (base 16) uppercase format.%%Prints a percent sign.
Instructions
To run the project and obtain libftprintf.a you need to run the following command:
make all
If you want to delete .o files you can use one of these following commands:
make clean
or
make fclean
If you want to check how the function is working, you need to compile the program with main function. Create main.c file and put following code:
#include "ft_printf.h"
int main(void)
{
char c;
char *str;
int i;
unsigned int u;
void *ptr;
c = 'A';
str = "Hello, world!";
i = -42;
u = 42;
ptr = &i;
// %c - character
ft_printf("Char: %cn", c);
// %s - string
ft_printf("String: %sn", str);
// %d / %i - integer
ft_printf("Integer (d): %dn", i);
ft_printf("Integer (i): %in", i);
// %u - unsigned integer
ft_printf("Unsigned: %un", u);
// %x / %X - hexadecimal
ft_printf("Hex (lowercase): %xn", u);
ft_printf("Hex (uppercase): %Xn", u);
// %p - pointer
ft_printf("Pointer: %pn", ptr);
// %% - percent sign
ft_printf("Percent: %%n");
return (0);
}
Now you can compile the program using this command:
cc -Wall -Wextra -Werror ft_printf.c ft_puthex.c ft_putnbr.c ft_putptr.c ft_putstr.c main.c
Logic explanation
Firstly, we need to understand what are variadic function and how they are used.
Let’s look on my ft_printf function:
int ft_printf(const char *str, ...)
{
int i;
int count;
va_list list;
i = 0;
count = 0;
va_start(list, str);
while (str[i])
{
if (str[i] == '%' && str[i + 1])
{
count += handle_specifier(str[i + 1], list);
i += 2;
}
else
{
write(1, &str[i], 1);
count++;
i++;
}
}
va_end(list);
return (count);
}
My function prototype accepts a string along with a variable number of arguments (const char *str, ...). To access these additional arguments, we need to initialize a list that allows us to iterate through them.
I declared a variable named list of type va_list, which is defined in <stdarg.h>.
After that I initialized that list using va_start(list, str) command.
Now I can access those variable using va_arg(args, type), where type can be: int, char * and etc.
Next step, my function needs to find a % sign in the string, check what’s the specifier behind it and based on that information, decide what to do.
I iterated through a string and was looking for % sign:
while (str[i])
{
if (str[i] == '%' && str[i + 1])
{
count += handle_specifier(str[i + 1], list);
i += 2;
}
else
{
write(1, &str[i], 1);
count++;
i++;
}
}
When I found a % sign, I also checked the next character behind it (if it exists). If yes, then I call handle_specifier function. Let’s look on its code:
int handle_specifier(char c, va_list args)
{
int count;
count = 0;
if (c == 's')
count += ft_putstr(va_arg(args, char *));
else if (c == 'c')
count += ft_putchar(va_arg(args, int));
else if (c == '%')
count += ft_putchar('%');
else if (c == 'i' || c == 'd')
count += ft_putnbr(va_arg(args, int));
else if (c == 'u')
count += ft_putnbr_unsigned(va_arg(args, unsigned int));
else if (c == 'x')
count += ft_puthex(va_arg(args, unsigned int));
else if (c == 'X')
count += ft_puthex_up(va_arg(args, unsigned int));
else if (c == 'p')
count += ft_putptr((unsigned long)va_arg(args, void *));
return (count);
}
This function determines the format specifier and, based on it, calls the appropriate helper function. For example, if the specifier is c, it calls ft_putchar to print a character. To retrieve that character, I use the va_arg function. Since a char is only 1 byte, it is promoted to an int when passed through va_arg, which is the standard behavior.
Also an important note: printf function returns a value of characters it printed, thats why I initilized count variable everywhere and counting every print. I also modified each of my helper functions from libft to return an integer, so I can do something like count += ft_putchar(va_arg(args,int)); without compilation errors.

Leave a Reply