Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Coding printf with array of function pointers

Tags:

arrays

c

I am trying to code the printf function. The problem is that my code is getting very messy and I need some help to try to make it organized and working (hopefully). I have been told that I should use "array of function pointers" so I tried below (ft_print_it) as you can see but I do not know how to how to structure my code so that I can use a big array of function pointer to put every function like int_decimal_octal and friends. Can you help me on that? Where can I call them from?

Also, I realized the little function below (cast_in_short) is giving me the same result as printf if I write the output with my ft_putnbr. My second question is thus: Can I make my printf work with little functions like this? Thank you so much.

int cast_in_short(int truc)
{
    truc = (short)truc;
    return (truc);
}    

/*
     here in the main I noticed that I get the same behaviour
     between my putnbr and printf thanks to my little function
     cast_in_short. This is the kind of function I want to use
     and put into an array of pointer of functions in order
     to make my printf work
*/

int main()
{
    int n = 32769;
    n = cast_in_short(n);

    ft_putnbr(n);

    printf("\n");

    return (0);
}

/* function to launch ft_print_it */

int ft_print_str_spec(va_list ap, char *flag)
{
    if (ft_strlen(flag) == 1)
        ft_putstr(va_arg(ap, char *));
    else
    {
        ft_nbzero(ap, flag, 0);
        ft_putstr(va_arg(ap, char *));
    }
    return (1);
}

int ft_print_oct(va_list ap, char *flag)
{
    if (ft_strlen(flag) == 1)
        ft_putnbr(decimal_octal((va_arg(ap, int))));
    else
    {
        ft_nbzero(ap, flag, 1);
        ft_putnbr(decimal_octal((va_arg(ap, int))));
    }
    return (1);
}


#include "libft.h"
#include <stdarg.h>
#include <stdio.h>

char    *ft_strjoin2(char const *s1, char const c);

#include "libft.h"
#include <stdarg.h>
#include <stdio.h>

int decimal_octal(int n) /* Function to convert decimal to octal */
{
    int rem;
    int i;
    int octal;

    i = 1;
    octal = 0; 

    while (n != 0)
    {
        rem = n % 8;
        n /= 8;
        octal += rem * i;
        i *= 10;
    }
    return (octal);
}
like image 396
zakk8889 Avatar asked Sep 26 '22 17:09

zakk8889


People also ask

Can we have an array of function pointers?

4) Like normal pointers, we can have an array of function pointers. Below example in point 5 shows syntax for array of pointers. 5) Function pointer can be used in place of switch case.

How do you pass an array to a function with pointer?

How Arrays are Passed to Functions in C/C++? A whole array cannot be passed as an argument to a function in C++. You can, however, pass a pointer to an array without an index by specifying the array's name. In C, when we pass an array to a function say fun(), it is always treated as a pointer by fun().

What is array of function pointer?

Array of Function PointersWe declare and define four functions which take two integer arguments and return an integer value. These functions add, subtract, multiply and divide the two arguments regarding which function is being called by the user.

How do you declare an array of function pointers in C++?

You can declare an array of function pointers in C++ using std::vector<std::function<>> notation, where you should also specify the template parameters for the std::function as needed. In this case, we inserted int(int, int) type to denote the functions that accept two int arguments and also have an int return type.


2 Answers

I think the best way to organize your code to avoid the function like your "flag_code" is to use an array of structure. With structure that contain a char (corresponding to the flag) and a function pointer.

For example :

typedef struct fptr
{
   char op;
   int (*ptr)(va_list);
} fptr;

And instatiate it like that (with { 'flag', name of the corresponding function} ) :

fptr  fptrs[]=
{
   { 's', ft_print_nb_spec },
   { 'S', ft_print_nb_up },
   { 0, NULL }
};

Then when you know have char after the % (the flag) you can do something like this :

  int i = -1;
  while (fptrs[++i].op != flag && fptrs[i].op != 0);
  if (fptrs[i].op != 0)
  {
     fptrs[i].ptr();
  } 

For exemple if flag = 'S' the while loop will stop when i = 1 and when you call fptrs[1].ptr() you will call the corresponding function in the structure.

like image 118
LapizLazuli Avatar answered Sep 29 '22 00:09

LapizLazuli


I think instead of making your code messy by using function pointers, because in the end you cannot specialize printf function without providing the format, in C there is no function overloading or template functions. My suggestion is to special printf function by type.

// print seperator
void p (int end)
{ printf(end?"\n":" "); }

// print decimal
void pi (long long n)
{ printf("%lld",n); }

// print unsigned
void pu (unsigned long long n)
{ printf("%llu",n); }

// print floating point
void pf (double n)
{ printf("%g",n); }

// print char
void pc (char n)
{ printf("%c",n); }

// print string
void ps (char* n)
{ printf("%s",n); }

Test try here

pi(999),p(0),pf(3.16),p(0),ps("test"),p(1);

Output

999 3.16 test

Another option

In theory you can define polymorphic print function in a struct, in case you can do something like this. I haven't tested this yet.

struct Node
{
    enum NodeType {Long,Double,Char,String} type;
    union {long l,double d,char c,char* s};
};

void p(Node* n)
{
    switch (n->type)
    {
        case Node::NodeType::Long: printf("%ld", n->l);
        case Node::NodeType::Double: printf("%g",n->d);
        case Node::NodeType::Char: printf("%c",n->c);
        case Node::NodeType::String: printf("%s",n->s);
    }
}
like image 26
Khaled.K Avatar answered Sep 29 '22 01:09

Khaled.K