ft_printf function

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 ar to 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.

Project description

Conversions

  • %c Prints a single character.
  • %s Prints a string.
  • %p The void * pointer argument has to be printed in hexadecimal format.
  • %d Prints a decimal (base 10) number.
  • %i Prints an integer in base 10.
  • %u Prints an unsigned decimal (base 10) number.
  • %x Prints a number in hexadecimal (base 16) lowercase format.
  • %X Prints 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.

Resources

  • man printf.3 – shows manual page for printf function.
  • printf Wikipedia page – Link is available here.
  • Guide for Variadic Functions – Link is available here.
  • AI wasn’t really used in this project.

Share This:

Leave a Reply

Your email address will not be published. Required fields are marked *