Search code examples
cprintfvariadic-functionsstdiovariadic

Why do my variadic functions in my printf function not work?


I need to recreate the printf function for a school project. My current function works flawlessly, except if there are two arguments.

If I do the following: ft_printf("%c%c", 'a', 'b');

it will print aa, instead of ab.

If I do the following: ft_printf("%c%d", 't', 29);

it will not print t29 like it's supposed to. Instead, it will print t116 as it does detect that I would like to print an int, but doesn't use the right argument (it converts "t" in its ascii value (116)).

I have included below the code of my main printffunction, the ft_analysis function (to find the flags), the ft_utilities_one function (which has some basic functions like putchar() for example) as well as the parsing function I'm using to parse the string given as primary argument. Due to how many code there is, I have only included the char printing function (ft_c_craft) as an example. If you need more clarity regarding how these functions are used, you can find here my printf repository.

ft_printf.c

int ft_printf(const char *str, ...)
{
    t_list  box;
    va_list argptr;

    va_start(argptr, str);
    ft_parser(argptr, (char *)str, &box);
    va_end(argptr);
    return (box.len);
}

ft_parser.c

static void ft_craft1(va_list argptr, t_list *box)
{
    if (box->type == 'c')
        ft_c_craft(va_arg(argptr, int), box);
    else if (box->type == 's')
        ft_s_craft(va_arg(argptr, char *), box);
    else if (box->type == 'd' || box->type == 'i')
        ft_di_craft(va_arg(argptr, int), box);
}

static void ft_craft2(va_list argptr, t_list *box)
{
    if (box->type == 'u')
        ft_u_craft(va_arg(argptr, unsigned int), box);
    else if (box->type == 'x')
        ft_xx_craft(va_arg(argptr, int), 0, box);
    else if (box->type == 'X')
        ft_xx_craft(va_arg(argptr, int), 1, box);
    else if (box->type == 'p')
        ft_p_craft(va_arg(argptr, unsigned long long), box);
}

static void ft_type_selector(va_list argptr, t_list *box)
{
    if (box->type == 'c' || box->type == 's' || box->type == 'd'
            || box->type == 'i')
        ft_craft1(argptr, box);
    else
        ft_craft2(argptr, box);
}

void        ft_parser(va_list argptr, char *str, t_list *box)
{
    int i;

    i = 0;
    while (str[i] != '\0')
    {
        if (str[i] == '%' && str[i + 1] != '%')
        {
            ft_analysis(&str[++i], box);
            while (ft_strchr("cspdiuxX", str[i]) == NULL)
                i++;
            if (ft_strchr("cspdiuxX", str[i]))
                box->type = str[i];
            ft_type_selector(argptr, box);
        }
        else if (str[i] == '%' && str[i + 1] == '%')
            ft_putchar(str[++i], box);
        else
            ft_putchar(str[i], box);
        i++;
    }
}

ft_analysis.c

static void ft_precision(char *str, t_list *box)
{
    box->precision = 0;
    while (*str != '\0')
    {
        if (*str == '.')
        {
            box->precision = ft_atoi_alpha(++str);
            return ;
        }
        str++;
    }
    return ;
}

static void ft_width(char *str, t_list *box)
{
    box->width = 0;
    while (*str != '\0' && *str != '.')
    {
        if (*str >= '0' && *str <= '9')
        {
            box->width = ft_atoi_alpha(str);
            return ;
        }
        str++;
    }
    return ;
}

static void ft_flag(char *str, t_list *box)
{
    box->fzero = 0;
    box->fplus = 0;
    box->fminus = 0;
    box->fspace = 0;
    while (*str != '\0' && (!(*str >= '1' && *str <= '9')))
        if (*str++ == '0')
            box->fzero += 1;
    else if (ft_strchr(str, '+'))
        box->fplus += 1;
    else if (ft_strchr(str, '-'))
        box->fminus += 1;
    else if (ft_strchr(str, ' '))
        box->fspace += 1;
    return ;
}

void        ft_analysis(char *str, t_list *box)
{
    ft_precision(str, box);
    ft_width(str, box);
    ft_flag(str, box);
}

ft_c_craft.c

static void ft_print_char(char c, t_list *box)
{
    if (box->fminus == 1)
    {
        ft_putchar(c, box);
        ft_super_putchar(box->width - 1, ' ', box);
        return ;
    }
    else if (box->fzero == 1)
        ft_super_putchar(box->width - 1, '0', box);
    else if (box->fminus == 0)
        ft_super_putchar(box->width - 1, ' ', box);
    ft_putchar(c, box);
    return ;
}

void    ft_c_craft(char c, t_list *box)
{
    if (box->width > 1)
        ft_print_char(c, box);
    else
        ft_putchar(c, box);
}

ft_utilities_one.c

void    ft_putchar(char c, t_list *box)
{
    write(1, &c, 1);
    box->len += 1;
}

void    ft_putstr(char *str, t_list *box)
{
    while (*str != '\0')
    {
        write(1, str++, 1);
        box->len += 1;
    }
}

void    ft_putstr_precision(char *str, t_list *box)
{
    int i;

    i = box->precision;
    while (*str != '\0' && i-- > 0)
    {
        write(1, str++, 1);
        box->len += 1;
    }
}   

void    ft_super_putchar(int len, char c, t_list *box)
{
    while (len-- > 0)
    {
        write(1, &c, 1);
        box->len += 1;
    }
}

long    ft_atoi_alpha(const char *nptr)
{
    long    result;

    result = 0;
    while (*nptr && ((*nptr >= 9 && *nptr <= 13) || *nptr == ' '))
        nptr++;
    if (*nptr == '-' || *nptr == '+')
        nptr++;
    while (*nptr && *nptr >= '0' && *nptr <= '9')
        result = result * 10 + (*nptr++ - '0');
    return (result);
}

Solution

  • If I do the following: ft_printf("%c%c", 'a', 'b');

    it will print aa, instead of ab.

    If I do the following: ft_printf("%c%d", 't', 29);

    it will not print t29 like it's supposed to. Instead, it will print t116 as it does detect that I would like to print an int, but doesn't use the right argument (it converts "t" in its ascii value (116)).

    visibly you do not progress and always use the first argument, this is because you give the va_list by value, so you use a copy of it and you cannot progress in the list of argument. Just give it by pointer

    in ft_printf

    ft_parser(&argptr, (char *)str, &box);
    

    and :

    static void ft_craft1(va_list *argptr, t_list *box)
    {
        if (box->type == 'c')
            ft_c_craft(va_arg(*argptr, int), box);
        else if (box->type == 's')
            ft_s_craft(va_arg(*argptr, char *), box);
        else if (box->type == 'd' || box->type == 'i')
            ft_di_craft(va_arg(*argptr, int), box);
    }
    

    etc