Как исправить мою реализацию `itoa`, чтобы она не выводила обратный вывод? - PullRequest
1 голос
/ 01 июня 2019

Я хочу преобразовать целое число в строку числовых символов в C.

Я пытался использовать itoa, но он нестандартный и не предоставляется моей библиотекой C.

Я пытался реализовать свой собственный itoa, но он не работает должным образом:

#include <stdlib.h>
#include <stdio.h>

char *itoa(int val, char *buf, int base)
{
    size_t ctr = 0;
    for( ; val; val /= base )
    {
        buf[ctr++] = '0' + (val % base);
    }
    buf[ctr] = 0;
    return buf;
}

int main(void)
{
    unsigned char c = 201;
    char *buf = malloc(sizeof(c)*8+1);
    itoa(c, buf, 2);
    puts(buf);
    free(buf);
}

Дает обратный вывод.

Например, если c равно 'A' и base равно 2, вывод будет таким: 0101101

Вывод, который я хочу получить, будет таким: 1011010

Как мне исправить эту проблему?


Похожие вопросы


Я уже видел этот вопрос: Есть ли конвертер printf для печати в двоичном формате?

Я не хочу, чтобы спецификатор формата printf выводил целое число как двоичный файл, я хочу преобразовать двоичный файл в строку.

Я уже видел этот вопрос: Вывести int в двоичном представлении, используя C

Хотя ответ преобразует целое число в строку двоичных цифр, это единственное, что он может сделать.


Ограничения


Я хочу, чтобы itoa мог работать с другими base с, такими как 10, 8 и т. Д., И печатать правильно (т. Е. 12345 означает "12345", а не * 1051) *).

Я не хочу использовать printf или sprintf для этого.

Меня не волнует длина строки, если результат верный.

Я не хочу преобразовывать целое число в символы ASCII, кроме числовых, за исключением base с больше 10, в этом случае символы могут быть буквенно-цифровыми.

Ответ должен точно соответствовать этому прототипу:

char *itoa(int val, char *buf, int base);

Может существовать функция с именем nitoa, которая имеет этот прототип и возвращает количество символов, необходимое для хранения результата itoa:

size_t nitoa(int val, int base);

Ответы [ 2 ]

4 голосов
/ 01 июня 2019

Как исправить мою реализацию itoa, чтобы она не печатала обратный вывод?

Вместо того, чтобы перевернуть строку, сформируйте ее справа налево.# 4 из @ user3386109


Я рекомендую, чтобы вспомогательная функция также получала в размере.

#include <limits.h>

char* itostr(char *dest, size_t size, int a, int base) {
  // Max text needs occur with itostr(dest, size, INT_MIN, 2)
  char buffer[sizeof a * CHAR_BIT + 1 + 1]; 
  static const char digits[36] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";

  if (base < 2 || base > 36) {
    fprintf(stderr, "Invalid base");
    return NULL;
  }

  // Start filling from the end
  char* p = &buffer[sizeof buffer - 1];
  *p = '\0';

  // Work with negative `int`
  int an = a < 0 ? a : -a;  

  do {
    *(--p) = digits[-(an % base)];
    an /= base;
  } while (an);

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

  size_t size_used = &buffer[sizeof(buffer)] - p;
  if (size_used > size) {
    fprintf(stderr, "Scant buffer %zu > %zu", size_used , size);
    return NULL;
  }
  return memcpy(dest, p, size_used);
}

Затем, чтобы обеспечить память, используйте составной литерал .

// compound literal C99 or later
#define INT_STR_SIZE (sizeof(int)*CHAR_BIT + 2)
#define MY_ITOA(x, base) itostr((char [INT_STR_SIZE]){""}, INT_STR_SIZE, (x), (base))

Теперь вы можете вызывать его несколько раз.

int main(void) {
  printf("%s %s %s %s\n", MY_ITOA(INT_MIN,10), MY_ITOA(-1,10), MY_ITOA(0,10), MY_ITOA(INT_MAX,10));
  printf("%s %s\n", MY_ITOA(INT_MIN,2), MY_ITOA(INT_MIN,36));
  return (0);
}

Выход

-2147483648 -1 0 2147483647
-10000000000000000000000000000000 -ZIK0ZK

Примечание: sizeof(c)*8+1слишком мал для INT_MIN, база 2.

1 голос
/ 01 июня 2019

Это решение работает для меня:

#include <errno.h>
#include <stdlib.h>
#include <string.h>

#define itoa lltoa
#define utoa ulltoa
#define ltoa lltoa
#define ultoa ulltoa
#define nitoa nlltoa
#define nutoa nulltoa
#define nltoa nlltoa
#define nultoa nulltoa

#define BASE_BIN 2
#define BASE_OCT 8
#define BASE_DEC 10
#define BASE_HEX 16
#define BASE_02Z 36

__extension__
char *ulltoa(unsigned long long val, char *buf, int base)
{
    int remainder;
    char c, *tmp = buf;

    if(base < BASE_BIN)
    {
        errno = EINVAL;
        return NULL;
    }

    do {
        remainder = val % base;
        if(remainder >= BASE_DEC) c = 'a' - BASE_DEC;
        else c = '0';
        *tmp++ = remainder + c;
        val /= base;
    } while(val);

    *tmp = 0;
    return strrev(buf);
}

__extension__
size_t nulltoa(unsigned long long val, int base)
{
    size_t size = 0;

    if(base < BASE_BIN)
    {
        errno = EINVAL;
        return 0;
    }

    if(!val) size++;

    for( ; val; val /= base, size++ );

    return size;
}

__extension__
char *lltoa(long long val, char *buf, int base)
{
    if(val < 0 && base > BASE_BIN)
    {
         val = -val;
         *buf++ = '-';
    }

    return ulltoa(val, buf, base);
}

__extension__
size_t nlltoa(long long val, int base)
{
    size_t size = 0;

    if(val < 0 && base > BASE_BIN)
    {
        val = -val;
        size++;
    }

    return size + nulltoa(val, base);
}
...