Coding printf with array of function pointers - 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);
}

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.

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);
}
}

Related

Error with the array returning through function

I need to read a word from main function and convert the characters in UCASE if the first character is LCASE and vice versa using the user defined function.I tried ways for returning the array from function but still I am lacking some core ideas. Please debug this program and explain the way it works.
#include <stdio.h>
#include <string.h>
int* low (char str)
{
int i;
for (i=1; i<strlen(str);i++)
{
if(str[i]<91)
{
str[i]=str[i]+32;
}
else
{
}
}
return &str;
}
int* high (char str[50])
{
int i;
for (i=0; i<strlen(str);i++)
{
if(str[i]>91)
{
str[i]=str[i]-32;
}
else
{
}
}
return &str;
}
void main()
{
char str[50];
char* strl;
printf("Enter any string....\n");
scanf("%s",str);
if (str[0]<91)
{
*strl=low(str);
}
else
{
*strl=high(str);
}
printf("Converted string is %s.",*strl);
}
There is already a problem here:
So if you are saying this code is perfect and you want us to debug it and explain how (on earth) this works, then here you go.
In function int* low (char str), you have if(str[i]<91). Thats a problem right there. str is a char received as an argument, and hence str[i] is a straight compile-time error.
Another one to deal with is the return statement.
You have a statement:
return &str;
which would return the address of str, which by the way is a char, whereas function low is supposed to return a pointer to an int.
The same is applicable to high function as well.
Suggestion: Leave aside this bad code and get a beginner level C programming book first. Read it and the try some codes out of it.
A few inputs for improvement: (Which you may not comprehend)
change
void main()
to
int main(void)
Why? Refer this legendary post: What should main() return in C and C++?
Secondly, int both functions you are using strlen() in loop which will always return a fixed value. So, instead of
for (i=0; i<strlen(str);i++)
I'd suggest,
size_t strlength = strlen(str);
for (i=0; i < strlength; i++)
You can try the code and method as below:
#include <stdio.h>
#include <string.h>
char* caseConverter (char *str)
{
int i;
for (i=0; i<strlen(str);i++)
{
if(str[i]>=65 && str[i]<=90)
{
str[i]=str[i]+32; //To lower case
}
else if((str[i]>=97 && str[i]<=122))
{
str[i]=str[i]-32; //To upper case
}
else
printf("%c is not an alphabet \n",str[i]);
}
return str;
}
void main()
{
char inputStr[50]= "Stubborn";
char* opStr= caseConverter(inputStr);
printf("Converted string is %s",opStr);
}

incompatible pointer compiler error

I have this assignment where we expected to write a program that takes
a positive integer number as a command line argument and prints the
smallest prime number bigger than the given number.
The main function shouldn't be edited, however, you may create a
header file for defining needed functions.
So far this is what I came up with, I just can't find out what
is wrong with my program. Help is appreciated.
main function: I can't edit the main function, however, you can create a header
#include "slow-prime.h"
int main(int argc, char *argv[]) {
int num;
int nxt;enter code here
int ret = EXIT_FAILURE;
if (argc < 2) {
printf("error: missing command line argument\n");
goto ERROR;
if (get_number(argv[1], &num)) {
printf("error: %s not a number\n", argv[1]);
goto ERROR;
}
next_prime(num, &nxt);
printf("%d\n", nxt);
ret = EXIT_SUCCESS;
ERROR:
return ret;
}
}
needed functions are created in the slow-prime.h
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
// define true and false
#define true 1
#define false 0
// check whether the numer is prime or mnot
int isPrime(int num){
if (num < 2) {
return false;
}
for (int i = 2; i <= num / i; i++) {
if (num % i == 0) {
return false;
}
}
return true;
}
// get number
void get_number(char *argv[], int num) {
num = atoi(argv[1]);
}
// loop through the numbers/ and pick the one
void next_prime(int num, int next){
for(int i = 2; i < 80; i++){
if (isPrime(i) == true){
next = i;
if (next > num) {
return exit(0);
}
}
}
}
Error Message:
error
You have:
void get_number(char *argv[], int num) {
and you are calling the function using:
if (get_number(argv[1], &num)) {
You are passing the wrong types for both arguments.
argv[1] is of type char*.
&num is of type int*.
I think you should to use:
void get_number(char *arg, int *num) {
and change the implementation slightly.
void get_number(char *arg, int *num) {
*num = atoi(arg);
}
Also, given that get_number returns void, you cannot use it in the conditional of an if statement. You'll need to change its return type to something else, an int perhaps. In that case, using atoi might not be appropriate. atoi returns 0 when it cannot convert the string to an int. If 0 a valid value for you, then atoi is not a good choice. However, you can use sprintffor all cases.
If 0 is not a valid number, you can use:
int get_number(char *arg, int *num) {
*num = atoi(arg);
return *num;
}
If 0 is a valid number, you can use:
int get_number(char *arg, int *num) {
return (sprintf(arg, "%d", num) == 1);
}

Recursive Function of Characters To Binary (ASCII)

I bought a Programming book at a yard sale for $2 because I've always wanted to learn how to code but don't have the money and resources for school. I've gotten through the first few chapters just fine, but I've also had the solutions to the problems I was working on. But the chapter is missing a few of the pages after the chapter summary when they start listing problems. I was wondering if you guys could help me out.
Here is the problem. Note: Needs to use a recursive function.
#include <stdio.h>
#include <stdlib.h>
void binaryPrinter(int value, int *numberOfOnes);
void print(char c);
//You do not need to modify any code in main
int main()
{
char value;
int result = 1;
while(result != EOF)
{
result = scanf("%c",&value);
if(result != EOF && value != '\n')
{
print(value);
}
}
}
//#hint: This is called from main, this function calls binaryPrinter
void print(char c)
{
}
//#hint: this function is only called from print
void binaryPrinter(int value, int *numberOfOnes)
{
}
void print(char c)
{
int n = CHAR_BIT;
binaryPrinter((unsigned char)c, &n);
putchar('\n');
}
void binaryPrinter(int value, int *numberOfOnes)
{
if((*numberOfOnes)--){
binaryPrinter(value >> 1, numberOfOnes);
printf("%d", value & 1);
}
}

Undeclared identifier in C function

When I compile the following C function / program I get errors like "missing ';' before 'type' 'remainder' : undeclared identifier" - what is wrong with this function?
#include <stdio.h>
void conversionTo(int number,int base) {
if(number==0)
return;
int remainder=number%base;
conversionTo((number/base),base);
if(remainder<10)
printf("%c",'0'+remainder);
else
printf("%c",'a'-10+remainder);
}
int main() {
conversionTo(int number,int base);
return 0;
}
I'm not a C expert, but from experience very long ago I believe you cannot declare variables in the middle of a function.
Also, it's unclear what you are trying to do with the function / print statements.
Try this:
#include <stdio.h>
void conversionTo(int number,int base) {
int remainder=number%base;
if(number==0)
return;
conversionTo((number/base),base);
if(remainder<10)
printf("%c",'0'+ remainder); // Through the way ASCII works that gives the ASCII rep
// of the remainder.
else
printf("%c",'a'-10+remainder); // Hex digits (A-F).
}
int main() {
conversionTo(/*Any number here*/10, /*any base number here*/2);
return 0;
}
You need to defines variables, then they can be used.
So this:
int main() {
conversionTo(int number,int base);
return 0;
}
should become this:
int main(void)
{
int number;
int base:
number = 47;
base = 11;
conversionTo(number, base);
return 0;
}
Also non C99 compliant compilers do not like having variables declared in the middle of a context:
void conversionTo(int number,int base) {
if(number==0)
return;
int remainder=number%base; /* this would fail. */
conversionTo((number/base),base);
To get around this open another context:
void conversionTo(int number,int base) {
if(number==0)
return;
{
int remainder=number%base;
conversionTo((number/base),base);
if(remainder<10)
printf("%c",'0'+remainder);
else
printf("%c",'a'-10+remainder);
}
}
You have to invoke your function with a value or variable, not a declaration:
conversionTo(123, 10); // using constant value
or
int number = 123, base = 10; // variable declaration
conversionTo(number, base); // using variable
You are calling your function wrong - pass the arguments this way:
conversionTo(2,2); // assuming you want to convert 2 to binary
or
int number = 123, base = 10;
conversionTo(number, base); // note this is not the same number and base as in the definition of your conversionTo function
Full code:
#include <stdio.h>
void conversionTo(int number,int base)
{
if(number==0)
return;
int remainder=number%base;
conversionTo((number/base),base);
if(remainder<10)
printf("%c",'0'+remainder);
else
printf("%c",'a'-10+remainder);
}
int main()
{
conversionTo(2,2); // assuming you want to convert 2 to binary
return 0;
}
There are 3 things when using functions:
Function declaration / prototype - the prototype of your function is:
void conversionTo(int ,int );
Function definition:
void conversionTo(int number,int base /* Parameter list*/)
{
// your functionality
}
Function call where you pass your arguments to your function:
conversionTo(2,2);
The statement conversionTo(int number,int base); simply re-declares it. Try this even this will compile:
int main()
{
printf("Hello World");
int main();
}
conversionTo(int number, int base)
is the syntax for declaring which parameters the function can take. To actually call the function, you need to omit the type (assuming you have variables of the respective name)
int number = 5;
int base = 10;
conversionTo(number, base); // <-- no int here!
Or you can use numbers directly:
conversionTo(5, 10);
Your function definition number and base in your function declaration void conversionTo(int number, int base) are the names that the values passed to it will have inside the function. So, if you call conversionTo(2,5), 2 will be seen inside the function as number, while 5 will be seen as base.
If you want to use variables instead of contants to call the function, you could do that:
int main()
{
int base = 2;
int number = 5;
conversionTo(base, number);
return 0;
}
In this confusing example, the variables base and value have value 2 and 5, respectively. But as you pass them to the function, the values inside it will be number = 2 and base = 5. This shows that those variables are actually different, despite of having the same name.
You should compile with $CC -std=c99, to enable declaring variables in the middle of a block.
(see section 6.8 in the specification)
The declaration "int remainder" must come before any statements in a block.
A declaration may have an initializer as you have here.
You could do:
void conversionTo(int number,int base) {
if (number > 0) {
int remainder...
}
}
since the function will not work with negative numbers.
To fix the other bugs in the routine:
void conversionTo(int number,int base)
{
if(number>=0&&base>0&&base<=36)
{
int remainder=number%base;
number/=base;
if(number>0)conversionTo(number,base);
printf("%c",(remainder<10)?'0'+remainder:'a'+remainder-10);
}
}
This will print a 0 if number is zero and only recurse if needed.

The showbits() function

While reading a book called "Let us C" I read that a function showbit() exists which can show you the bits of the number. There wasn't any special header file mentioned for it. Searched for it on the internet and didn't found anything useful. Is there such a function? I want this to print the binary of decimal numbers. Else please give me a replacement function. Thanks
All integers are actually in binary in your computer. Its just that it is turned into a string that is the decimal representation of that value when you try to print it using printf and "%d". If you want to know what it looks like in some other base (e.g. base 2 or binary), you either have to provide the proper printf format string if it exists (e.g. "%x" for hex) or just build that string yourself and print it out.
Here is some code that can build the string representation of an integer in any base in [2,36].
#include <stdio.h>
#include <string.h>
char digits[]="01234567890ABCDEFGHIJKLMNOPQRSTUVWXYZ";
void reverse(char* start, char* end)
{
for(end--;start<end;start++,end--)
{
char t=*start;
*start=*end;
*end=t;
}
}
int base_change(int n, int base,char* buffer)
{
int pos=0;
if (base>strlen(digits))
return -1;
while(n)
{
buffer[pos]=digits[n%base];
n/=base;
pos++;
}
buffer[pos]='\0';
reverse(buffer,buffer+pos);
return 0;
}
int main()
{
char buffer[32];
int conv=base_change(1024,2,buffer);
if (conv==0) printf("%s\n",buffer);
return 0;
}
You can also try this snippet which uses bit-shifting:
EDIT: (I've made it more portable)
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define BITS_IN_BYTE 8
#define INTEGRAL_TYPE unsigned int
void showBits(INTEGRAL_TYPE x) {
int i;
static int intSizeInBits = sizeof(INTEGRAL_TYPE) * BITS_IN_BYTE;
static char symbol[2] = {'0','1'};
char * binary = (char*) malloc(intSizeInBits + 1);
memset(binary, 0, intSizeInBits + 1);
for (i=0; i< intSizeInBits; i++) {
binary[intSizeInBits-i-1] = symbol[(x>>i) & 0x01];
}
printf("%s\n", binary);
free(binary);
}
int main() {
showBits(8698513);
return 0;
}
HTH!
This is a very simple solution for printing the bits of an integer
int value = 14;
int n;
for (n=8*sizeof(int)-1;n>=0;n--) {
printf("%d",(value >>n)&1);
}
The book "Let Us C" doesn't define it as a built-in function. The showbits() function is defined in later part of the book as a complete user defined function as I personally went through it. This answer is to anyone who haven't reached that later part of the book and are stuck at the first appearance of the function in the book.
you need to look here
#downvoter It works fine in c also. You just need to reformat your code in c-style.
#include <stdlib.h>
#include <stdio.h>
int main()
{
char buffer[20];
int i = 3445;
_itoa( i, buffer, 2 );
printf("String of integer %d (radix 2): %s",i,buffer);
return 0;
}
*you need to save your file as .c in MSVC++ for _itoa() to work.*
this is the header file for showbits
void showbits(unsigned int x)
{
int i;
for(i=(sizeof(int)*5)-1; i>=0; i--)
(x&(1u<<i))?putchar('1'):putchar('0');
printf("\n");
}
No there is no pre built function and you do not need to include any specific header file.
You will have to provide implementation for function showbits(int).
#include <stdio.h>
void showbits(int);
int main()
{
int j,k;
for(j=0;j<=11;j++)
{
printf("\nBinary value of decimal %d is :",j);
showbits(j);
}
return 0;
}
showbits(int n){
int i,k,andmask;
for(i = 15;i>=0;i--){
andmask = 1<<i;
k = n & andmask;
k==0 ? printf("0"):printf("1");
}
}
If you want to print out the bits of a float, for example you could do something like:
float myFloat = 45.2;
for (int n=0;n<8*sizeof(float);n++) {
printf("%d",(myFloat>>n)&1);
}

Resources