0
\$\begingroup\$

As an educational exercise, I would like to make this code more efficient, with fewer lines, without using other standard functions.

The goal here is to convert a number to X base and display it, (sample for hexadecimal) including 0x0 => 0, or 0x4096 => 4096.

int     print_hex(int number, int base)
{
    int     i;
    int     len;
    char    c;
    char    buffer[base];

    if (!number)
    {
        putchar('0');
        return 1;
    }
    i = 0;
    while (i < base && number > 0)
    {
        c = "0123456789abcdef"[number % base];
        buffer[i] = c;
        number /= base;
        i++;
    }
    buffer[i] = '\0';
    len = i;
    while (i--)
        putchar(buffer[i]);
    return (len);
}
\$\endgroup\$
2
\$\begingroup\$

Seems strange to pass base and call the function ...hex...().

Easier to use unsigned rather than int.

if (!number) block not needed if a do {} while (number); loop used.

char buffer[base]; is the wrong sized buffer. Need is more like "log(INT_MAX, base) + 1".


to make this code more efficient,

speed: Code is calling putchar() repetitively. The amount of processing there can well exceed all OP's code. Reducing I/O calls should be then the goal. E.g. Call fputs() once.

// a fast version

int print_fast(unsigned number, unsigned base) {
  char buf[sizeof number * CHAR_BIT + 1];
  char *end = &buf[sizeof buf] - 1;
  *end = '\0';
  do {
    end--;
    *end = "0123456789abcdef"[number % base];
    number /= base;
  } while (number);
  fputs(end, stdout);
  return (int) (&buf[sizeof buf] - end - 1);
}

with fewer lines,

See Code Golf for such. Note that reducing lines often goes against efficiently.

// A terse recursive solution

int print_terse(unsigned number, unsigned base) {
  int count = 1;
  if (number >= base) {
    count += print_short(number / base, base);
  }
  putchar("0123456789abcdef"[number % base]);
  return count;
}

without using other standard functions.

Not possible. Some library I/O function needed.


How about a full featured signed one?

Note the buffer needs to be 34 for a 32 bit int.

#include <assert.h>
#include <limits.h>
#include <stdio.h>

int print_int(int number, int base) {
  assert(base >= 2 && base <= 36);
  char buf[sizeof number * CHAR_BIT + 2];
  char *end = &buf[sizeof buf] - 1;
  *end = '\0';

  // Form the negative absolute value
  // Negatives used to cope with `INT_MIN`
  int n = (number > 0) ? -number : number;

  do {
    end--;
    *end = "0123456789abcdefghijklmnopqrstuvwxyz"[-(n % base)];
    n /= base;
  } while (n);

  if (number < 0) {
    end--;
    *end = '-';
  }

  fputs(end, stdout);
  return (int) (&buf[sizeof buf] - end - 1);
}

int main(void) {
  printf(" %d\n", print_int(0, 10));
  printf(" %d\n", print_int(INT_MAX, 36));
  printf(" %d\n", print_int(INT_MIN, 2));
  return 0;
}

Output

0 1
zik0zj 6
-10000000000000000000000000000000 33
\$\endgroup\$
  • \$\begingroup\$ @ken Why did you select number as int, which is often 32-bit if your goal is 64-bit? Suggest for your next coding, if the goal is to "display the numbers of 64 bits." use a type that is at least 64-bit like long long, unsigned long long, intmax_t, uintmax_t or exactly 64-bit: int64_t, uin64_t. Also then be clear: are you working with signed or unsigned types? \$\endgroup\$ – chux - Reinstate Monica Feb 9 at 17:31
2
\$\begingroup\$

Your code does not handle negative numbers. As it is, it will print nothing. The code should be changed to either handle the negatives properly, or take number as an unsigned where it is not an issue.

Your use of base as the length of the array to store the converted number in is incorrect. A 32-bit integer will potentially need 32 characters to display the entire number, assuming no zero byte terminator (see below). buffer should be declared as a fixed size, large enough to hold the longest possible string. You could then eliminate the i < base check from your while loop.

The initial check of if (!number) can be eliminated by changing your while loop into a do/while look.

If you're looking for brevity in code lines, the body of the loop can be reduced to two statements, although it is more readable with three or four.

The assignment of a 0 byte to the end of buffer is unnecessary in this context since you never pass buffer to a function that requires it.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.