Написание функции itoa

Вот базовая функция itoa, которую я написал, пытаясь использовать рекурсию:

void itoa(int number, char buffer[])
{
    static int idx=0, size=0;
    if (number == 0) {
        buffer[size] = '';
        idx = size = 0; // reset for next call
    }
    else {
        size++, idx++;
        itoa(number/10, buffer);
        buffer[size-idx--] = (number % 10) + '0';
    }
}

Как это выглядит? Это не потокобезопасно из-за статики, но является ли это проблемой для такой функции, как эта? Если да, то как я могу это обновить? Как еще я мог бы улучшить его?

1 ответ
1

Как это выглядит?

Не так хорошо, как хотелось бы.

  1. Не потокобезопасный.

  2. Плохо обрабатывает отрицательные числа.

  3. Формы "" с 0.

  4. Склонен к переполнению буфера.

  5. itoa() не является стандартной функцией, но обычно возвращает указатель.

Испытательная привязь

int main(void) {
  char buf[100];
  int test[] = {123, 456, 0, - 42, INT_MAX, INT_MIN};
  int n = sizeof test / sizeof *test;
  for (int i = 0; i < n; i++) {
    itoa(test[i], buf);
    printf("%-11d <%s>n", test[i], buf);
  }
  return 0;
}

Выход

123         <123>
456         <456>
0           <>
-42         <,.>
2147483647  <2147483647>
-2147483648 <./,),(-*,(>

Это не потокобезопасно из-за статики, но является ли это проблемой для такой функции, как эта?

Да. Ожидается потокобезопасность.


Если да, то как я могу это обновить? Как еще я мог бы улучшить его?

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

Но если один должен использовать рекурсию, подумать о добавлении проверки ошибок и тестирования различных типов int включая 0, INT_MAX, INT_MIN.

static char* itoa_helper(int number, size_t sz, char buffer[]) {
  if (sz == 0) {
    return NULL;
  }
  if (number <= -10) {
    buffer = itoa_helper(number / 10, sz - 1, buffer);
    if (buffer == NULL) {
      return NULL;
    }
    number %= 10;
  }
  *buffer = (char) ('0' - number);
  return buffer + 1;
}

char* itoa_recursive_alt(int number, size_t sz, char buffer[sz]) {
  if (sz == 0 || buffer == NULL) {
    return NULL;
  }
  char *s = buffer;

  if (number >= 0) {
    // Flip pos numbers to neg as neg range is greater.
    number = -number;
  } else {
    sz--;
    if (sz == 0) {
      *buffer="";
      return NULL;
    }
    *s++ = '-';
  }
  s = itoa_helper(number, sz-1, s);
  if (s == NULL) {
    *buffer="";
    return NULL;
  }
  *s = 0;
  return buffer;
}

int main(void) {
  char buf[100];
  int test[] = {123, 456, 0, -42, INT_MAX, INT_MIN};
  int n = sizeof test / sizeof *test;
  for (int i = 0; i < n; i++) {
    // char *s = itoa_recursive_alt(test[i], sizeof buf, buf);
    char *s = itoa_recursive_alt(test[i], sizeof buf, buf);
    if (s == NULL)
      s = "NULL";
    printf("%-11d <%s> <%s>n", test[i], s, buf);
  }
  return 0;
}

Выход

123         <123> <123>
456         <456> <456>
0           <0> <0>
-42         <-42> <-42>
2147483647  <2147483647> <2147483647>
-2147483648 <-2147483648> <-2147483648>

  • здорово, большое спасибо за то, что уделили время. Несколько вопросов: (1) какова обратная сторона отказа от скрытого отрицания? (2) в чем обратная сторона непрохождения size к функции itoa? Разве вызываемый объект не может определить размер и просто установить максимальную длину и вернуть ошибку, если есть усечение?

    — carl.hiass

  • 1

    @ carl.hiass 1) какова обратная сторона отказа от скрытого отрицания? -> Объясните, как вы собираетесь справиться INT_MIN что меньше чем -INT_MAX. 2) какова обратная сторона отсутствия передачи размера в функцию itoa? -> Риск переполнения буфера 3) Не может ли вызываемый объект определить размер и просто установить максимальную длину и вернуть ошибку, если есть усечение? —> Если вызывающий абонент не предоставит размер, вызываемый абонент не знает, сколько это слишком много. Вызываемый не контролирует объем буфера, который может быть использован. Но звонящий знает.

    — chux — Восстановить Монику

  • @ carl.hiass Был рекурсия требование?

    — chux — Восстановить Монику

  • нет, я только узнал об этом и пробовал с этим. Я думал, что это может избавить от необходимости реверсировать (что он делает), но, очевидно, есть много других проблем, которые он привносит.

    — carl.hiass

  • Я написал обновленную версию, основанную на вашей помощи — еще раз спасибо! codereview.stackexchange.com/questions/257428/…

    — carl.hiass

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *