thatbangaloreanguy
thatbangaloreanguy

Reputation: 25

Printing number as string in C without stdlibs

I am trying to do something similar to printf("My age is: %d\n", age); but I do not have access to the standard libraries. Instead, the print function I do have access to, print(), takes only a const char*.

I am not allowed to use sprintf or itoa or anything of that sort because that is simply not available. Is there a way I can print the number?

P.S. If you need more context, https://github.com/SpinalHDL/VexRiscv/issues/215 it is :)

Thanks in advance

Upvotes: 1

Views: 454

Answers (3)

Paul_Pedant
Paul_Pedant

Reputation: 166

It is kind of clumsy. You can get digits starting from the low end, using % 10 (modulus) to isolate the units digit and / 10 (integer divide) to shift the number to the right. You do that in a loop until the int goes down to zero. If the whole thing is zero, you have to set the '0' char yourself, because the loop will not then do the first iteration.

You need to add '0' to each digit to make it an ASCII digit, and you need to store the successive digits in a char array.

You need to append a NUL ('\0') char on the end as a string terminator.

Then you need to reverse the whole string, because the digits came out in reverse order. Alternatively, you can fill the char array from the end, but then you have to copy the whole string (including the NUL) up to the front of the buffer.

If the integer can be negative, you need to remember that, make it positive by subtracting it from zero, and stick a '-' on the end before you reverse it.

Sounds a lot, but the long2str function takes about 20 lines.

Edit: there is a recursive solution too. Going down the required depth, and saving the digits on the way back out, avoids the reverse sequence issue (including the minus sign), and creates the string without padding.

//.. Recursive solution.

//.. Base case.

void l2s_r (char **p, long int n)

{
    char d = (n % 10) + '0';
    if (n >= 10) l2s_r (p, n / 10);
    *((*p)++) = d;
}

//.. Wrapper case.

char *l2s (long int n)

{
static char s[24];
char *p = s;

    if (n < 0) { *p++ = '-'; n = 0 - n; }
    l2s_r (& p, n);
    *p = '\0';
    return (s);
}

Upvotes: 5

chux
chux

Reputation: 154250

As its been a week, (don't like to provide code for late night HW assignments), so some code to augment @Paul_Pedant descriptive answer.

An approach, in base 2 to 36, that forms the numeric string right to left.

It avoids undefined behavior of 0 - INT_MIN by forming the negative absolute value.

It uses div() rather than /, % to avoid implementation behavior with C89.

A do loop is used so print_int(0, base) prints "0".

#include <assert.h>
#include <limits.h>
#include <stddef.h>
#include <stdlib.h>
extern int print(const char *);

// Enough room for INT_MIN as a binary string.
#define MY_ITOA_BUF_SIZE (sizeof(int)*CHAR_BIT + 2)
#define MY_ITOA_BASE_MIN 2
#define MY_ITOA_BASE_MAX 36

// Negative values result in a string beginning with a '-' for all bases.
// Adjust as desired.
void print_int(int i, int base) {
  char buf[MY_ITOA_BUF_SIZE];
  char *p = &buf[sizeof buf - 1]; // Start from the "right".
  assert(base >= MY_ITOA_BASE_MIN && base <= MY_ITOA_BASE_MAX);

  *p = '\0';
  int value = i < 0 ? i : -i;  // negative absolute value
  do {
    div_t qr = div(value, base);
    *(--p) = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"[-qr.rem];  // Table look up
    value = qr.quot;
  } while (value);

  if (i < 0) {
    *(--p) = '-';
  }

  print(p);  // Like fputs(p, stdout)
}

Upvotes: 0

Shreenithi Iyer
Shreenithi Iyer

Reputation: 11

Something like this

int length(long long int no) 
{
 int count = 0;
 while (no != 0) 
 {
    no = no/10;
        count++;
 }
 return count;
}

void printer(long long int no)
{
   long long int temp = no;
   int i=0;
   char arr[10000];    
   i = length(no)-1;
   //Extract digits and fill `arr` backwards
   while(temp > 0)
   {
        arr[i] = (temp%10 + '0');    
        i--;
        temp = temp/10;
   }
   arr[length(no)] = '\n'; 
  char* p = &arr[0];
  println(p); //specific to: https://github.com/SpinalHDL/VexRiscv/blob/master/src/main/c/murax/hello_world/src/main.c
  //return p;
}

Upvotes: 1

Related Questions