Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

printf – implementation in C

This may be a silly question, but… I tried to implement printf, but for some reason the output I get is not exactly what I expected. any idea what it could be? I would appreciate some help.

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <stdarg.h> 

static int print(const char *restrict fmt, ...);
static int getfloat(float *);
static char *itoa(int, char *, int);
static void _strrev(char *);


int
main(void)
{
    float i1 = 0.0, i2 = 0.0, noi1 = 0.0, noi2 = 0.0, res = 0.0;

    print("weight - item 1: ");
    getfloat(&i1);

    print("no. of item 1: ");
    getfloat(&noi1);

    print("weight - item 2: ");
    getfloat(&i2);

    print("no. of item 2: ");
    getfloat(&noi2);

    res = ((i1 * noi1) + (i2 * noi2)) / (noi1 + noi2);
    print("%f\n", res);

    exit(EXIT_SUCCESS);
}


static int
print(const char *restrict fmt, ...)
{
    va_list ap;
    char buf[BUFSIZ] = {0}, tmp[20] = {0};
    char *str_arg;
    int i = 0, j = 0;

    va_start(ap, fmt);

    while (fmt[i] != '\0') {

        if (fmt[i] == '%') {
            i++;
            switch (fmt[i]) {
                case 'c':
                    buf[j] = (char)va_arg(ap, int);
                    j++;
                    break;

                case 'd':
                    itoa(va_arg(ap, int), tmp, 10);
                    strcpy(&buf[j], tmp);
                    j += strlen(tmp);
                    break;

                case 'f':
                    gcvt(va_arg(ap, double), 10, tmp);
                    strcpy(&buf[j], tmp);
                    j += strlen(tmp);
                    break;

                case 's':
                    str_arg = va_arg(ap, char *);
                    strcpy(&buf[j], str_arg);
                    j += strlen(str_arg);
                    break;

                default:
                    break;
            }
        } else { buf[j++ ] = fmt[i]; } 
        ++i;
    }
    fwrite(buf, j, 1, stdout);
    va_end(ap);
    return (j);
}


static int
getfloat(float *p)
{
    int c, sign = 0;
    float pwr = 0.0;


    while (c = getc(stdin), c == ' ' || c == '\t' || c == '\n')
        ;   /* ignore white spaces */
    
    sign = 1;   /* record sign */
    if (c == '+' || c == '-') {
        sign = (c == '+') ? 1 : -1;
        c = getc(stdin);
    }


    for (*p = 0.0; isdigit(c); c = getc(stdin))
        *p = 10.0 * *p + c - '0';

    if (c == '.') { c = getc(stdin); }

    for (pwr = 1.0; isdigit(c); c = getc(stdin)) {
        *p = 10.0 * *p + c - '0';
        pwr *= 10.0;
    }
    
    *p *= sign / pwr;
    if (c != EOF)
        ungetc(c, stdout);
    return (float)c;
}


static char *
itoa(int n, char *strout, int base)
{
    int i, sign;

    if ((sign = n) < 0)
        n -= n;

    i = 0;
    do {
        strout[i++] = n % base + '0';
    } while ((n /= base) != 0);

    if (sign < 0) { strout[i++] = '-'; }
    strout[i] = '\0';

    _strrev(strout);
    return (strout);
}


static void
_strrev(char *str)
{
    int i = 0, j = strlen(str) - 1;

    for ( ; i < j; ++i, --j) {
        int tmp = str[i];
        str[i] = str[j];
        str[j] = tmp;
    }
}

here is the output I get:
19.44444466

and this is the output that I expect: (or the one that I would at least like to receive, which is the one in itself that I get when I use printf)

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

19.444445 

>Solution :

   f, F   The double argument is rounded and converted to decimal
          notation in the style [-]ddd.ddd, where the number of
          digits after the decimal-point character is equal to the
          precision specification.  If the precision is missing, it
          is taken as 6;

https://man7.org/linux/man-pages/man3/printf.3.html

The default precision for %f is six so printf() is rounding the result to six decimal places.

You’d need to play with the ndigit argument to gcvt() which is the total number of significant digits (both before and after the decimal point). You are passing in 10 so your answer has two digits before the decimal and eight after for this particular number.

Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading