【发布时间】:2021-04-04 14:11:41
【问题描述】:
我需要为学校项目重新创建 printf 函数。我当前的功能完美无缺,除非有两个参数。
如果我执行以下操作:ft_printf("%c%c", 'a', 'b');
它将打印aa,而不是ab。
如果我执行以下操作:ft_printf("%c%d", 't', 29);
它不会像预期的那样打印t29。
相反,它会打印t116,因为它检测到我想打印一个int,但没有使用正确的参数(它将“t”转换为其ascii值(116))。
我在下面包含了我的主要printffunction 的代码、ft_analysis 函数(用于查找标志)、ft_utilities_one 函数(它具有一些基本函数,例如 putchar())以及解析函数 I 'm 用于解析作为主要参数给出的字符串。由于代码比较多,我只以char打印函数(ft_c_craft)为例。如果您需要更清楚地了解这些功能的使用方式,可以找到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);
}
【问题讨论】:
-
这就是为什么我在所有代码中都包含指向存储库的链接。你可以在这里找到它:github.com/maxdesalle/42/tree/main/ft_printf
-
t_list 是一个链表,我在其中存储有关参数的所有数据,包括宽度、精度、标志...
-
ft_c_craft, ft_s_craft,... 是负责打印参数的函数,按照存储在框内的数据(链表)。
-
抱歉,我是 stackoverflow 的新手。让我编辑我的问题。
-
无论是在这里还是在场外,都需要阅读大量代码。并且仅仅省略你认为不相关的部分并没有帮助,因为没有人可以构建它。再次阅读布鲁诺发布的链接。这个想法实际上是减少您的程序到一个更小的程序,它只包含重现错误所需的内容。它仍然应该是一个完整的程序,有人可以编译和运行(最好只在一个文件中),因此,例如,如果你删除了一个不相关的函数,你还需要删除调用它的代码
标签: c printf variadic-functions stdio variadic