Преобразовать целое число в строку без доступа к библиотекам - PullRequest
10 голосов
/ 21 октября 2010

Я недавно прочитал типовой вопрос собеседования:

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

Как бы вы поступили об этом?

Ответы [ 10 ]

9 голосов
/ 21 октября 2010

быстрый удар по нему: (отредактировано для обработки отрицательных чисел)

int n = INT_MIN;
char buffer[50];
int i = 0;

bool isNeg = n<0;

unsigned int n1 = isNeg ? -n : n;

while(n1!=0)
{
    buffer[i++] = n1%10+'0';
    n1=n1/10;
}

if(isNeg)
    buffer[i++] = '-';

buffer[i] = '\0';

for(int t = 0; t < i/2; t++)
{
    buffer[t] ^= buffer[i-t-1];
    buffer[i-t-1] ^= buffer[t];
    buffer[t] ^= buffer[i-t-1];
}

if(n == 0)
{
    buffer[0] = '0';
    buffer[1] = '\0';
}   

printf(buffer);
6 голосов
/ 21 октября 2010

Алгоритм легко увидеть на английском языке.

Дано целое число, например 123

  1. разделите на 10 => 123/10. Выход, результат = 12 и остаток = 3

  2. добавить 30h к 3 и добавить стек (добавление 30h преобразует 3 в представление ASCII)

  3. повторять шаг 1 до результата <10 </p>

  4. добавить 30h к результату и сохранить в стеке

  5. стек содержит число в порядке | 1 | 2 | 3 | ...

4 голосов
/ 21 октября 2010

Хороший пример можно найти в Интернете, посвященном реализации itoa. Вот один из них, избегая перевернуть строку в конце. Он опирается на статический буфер, поэтому будьте осторожны, если вы повторно используете его для других значений.

char* itoa(int val, int base){

    static char buf[32] = {0};

    int i = 30;

    for(; val && i ; --i, val /= base)

        buf[i] = "0123456789abcdef"[val % base];

    return &buf[i+1];

}
1 голос
/ 20 марта 2019

Преобразование целого числа в строку без доступа к библиотекам.

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

Использование neg_a в myitoa_helper() позволяет избежать неопределенного поведения с INT_MIN.

// Return character one past end of character digits.
static char *myitoa_helper(char *dest, int neg_a) {
  if (neg_a <= -10) {
    dest = myitoa_helper(dest, neg_a / 10);
  }
  *dest = (char) ('0' - neg_a % 10);
  return dest + 1;
}

char *myitoa(char *dest, int a) {
  if (a >= 0) {
    *myitoa_helper(dest, -a) = '\0';
  } else {
    *dest = '-';
    *myitoa_helper(dest + 1, a) = '\0';
  }
  return dest;
}

void myitoa_test(int a) {
  char s[100];
  memset(s, 'x', sizeof s);
  printf("%11d <%s>\n", a, myitoa(s, a));
}

Тестовый код и вывод

#include "limits.h"
#include "stdio.h"

int main(void) {
  const int a[] = {INT_MIN, INT_MIN + 1, -42, -1, 0, 1, 2, 9, 10, 99, 100,
      INT_MAX - 1, INT_MAX};
  for (unsigned i = 0; i < sizeof a / sizeof a[0]; i++) {
    myitoa_test(a[i]);
  }
  return 0;
}

-2147483648 <-2147483648>
-2147483647 <-2147483647>
        -42 <-42>
         -1 <-1>
          0 <0>
          1 <1>
          2 <2>
          9 <9>
         10 <10>
         99 <99>
        100 <100>
 2147483646 <2147483646>
 2147483647 <2147483647>
1 голос
/ 21 октября 2010

Внедрение функции itoa() кажется легкой задачей, но на самом деле вам нужно позаботиться о многих аспектах, связанных с вашими конкретными потребностями.Я предполагаю, что в интервью вы должны будете дать некоторые подробности о вашем пути к решению, а не копировать решение, которое можно найти в Google (http://en.wikipedia.org/wiki/Itoa)

Вот некоторые вопросы, которые вы можете задать себеили интервьюер:

  • Где должна находиться строка (неправильно передана пользователем? статическая переменная?)
  • Должен ли я поддерживать числа со знаком?
  • Должен лия поддерживаю число с плавающей запятой?
  • Должен ли я поддерживать другие базы, а не 10?
  • Нужна ли нам какая-либо проверка ввода?
  • Ограничена ли выходная строка в части длины?

и т. Д.

1 голос
/ 21 октября 2010

Предположим, что это десятичное число, а затем примерно так:

   int num = ...;
   char res[MaxDigitCount];
   int len = 0;
   for(; num > 0; ++len)
   {
      res[len] = num%10+'0';
      num/=10; 
   }
   res[len] = 0; //null-terminating

   //now we need to reverse res
   for(int i = 0; i < len/2; ++i)
   {
       char c = res[i]; res[i] = res[len-i-1]; res[len-i-1] = c;
   }   
1 голос
/ 21 октября 2010

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

Я бы также неоднократно использовал операторы / и %.

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

0 голосов
/ 17 мая 2018

Чем быстрее, тем лучше?

unsigned int findDigits(long long x)
{
    int i = 1;
    while ((x /= 10) && ++i);
    return i;
}
// return the number of digits in x.
unsigned int digits(long long x)
{
    x < 0 ? x = -x : 0;
    return x < 10 ? 1 :
        x < 100 ? 2 :
        x < 1000 ? 3 :
        x < 10000 ? 4 :
        x < 100000 ? 5 :
        x < 1000000 ? 6 :
        x < 10000000 ? 7 :
        x < 100000000 ? 8 :
        x < 1000000000 ? 9 :
        x < 10000000000 ? 10 : findDigits(x);
}


char tochar(unsigned short from)
{
    return from == 0 ? '0' :
        from == 1 ? '1' : from == 1 ? '1' : from == 2 ? '2' :
        from == 3 ? '3' : from == 4 ? '4' : from == 5 ? '5' :
        from == 6 ? '6' : from == 7 ? '7' : from == 8 ? '8' :
        from == 9 ? '9' : '\0';
}

char * tostring(long long from)
{
    unsigned char negative = from < 0;
    unsigned int i = digits(from);
    char* to = (char*)calloc(1, i + negative);
    if (negative && (*to = '-') & (from = -from) & i++);
    *(to + i) = 0;
    while ((i>0+negative) && (*(to + (--i)) = tochar(((from) % 10))) | (from /= 10));
    return to;
}

Если вы хотите выполнить отладку, вы можете разбить условия (инструкции) на
строк кода внутри области видимости {}.

0 голосов
/ 21 октября 2010

Чуть дольше, чем решение:

static char*
itoa(int n, char s[])
{
    int i, sign;

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

    i = 0;

    do 
    {      
        s[i++] = n % 10 + '0';  
    } while ((n /= 10) > 0);   

    if (sign < 0)
        s[i++] = '-';

    s[i] = '\0';
    reverse(s);

    return s;
} 

Реверс:

int strlen(const char* str)
{
   int i = 0;
   while (str != '\0')
   {
       i++;
       str++;
   }

   return i;
}

static void
reverse(char s[])
{
    int i, j;
    char c;

    for (i = 0, j = strlen(s)-1; i<j; i++, j--) {
        c = s[i];
        s[i] = s[j];
        s[j] = c;
    }
}

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

0 голосов
/ 21 октября 2010

Вот простой подход, но я подозреваю, что если вы включите его как есть, не понимая и не перефразируя его, ваш учитель будет знать, что вы только что скопировали его из сети:

char *pru(unsigned x, char *eob)
{
    do { *--eob = x%10; } while (x/=10);
    return eob;
}

char *pri(int x, char *eob)
{
    eob = fmtu(x<0?-x:x, eob);
    if (x<0) *--eob='-';
    return eob;
}

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

...