Вот базовая функция 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 ответ
Как это выглядит?
Не так хорошо, как хотелось бы.
Не потокобезопасный.
Плохо обрабатывает отрицательные числа.
Формы
""
с 0.Склонен к переполнению буфера.
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
@ carl.hiass 1) какова обратная сторона отказа от скрытого отрицания? -> Объясните, как вы собираетесь справиться
INT_MIN
что меньше чем-INT_MAX
. 2) какова обратная сторона отсутствия передачи размера в функцию itoa? -> Риск переполнения буфера 3) Не может ли вызываемый объект определить размер и просто установить максимальную длину и вернуть ошибку, если есть усечение? —> Если вызывающий абонент не предоставит размер, вызываемый абонент не знает, сколько это слишком много. Вызываемый не контролирует объем буфера, который может быть использован. Но звонящий знает.— chux — Восстановить Монику
@ carl.hiass Был рекурсия требование?
— chux — Восстановить Монику
нет, я только узнал об этом и пробовал с этим. Я думал, что это может избавить от необходимости реверсировать (что он делает), но, очевидно, есть много других проблем, которые он привносит.
— carl.hiass
Я написал обновленную версию, основанную на вашей помощи — еще раз спасибо! codereview.stackexchange.com/questions/257428/…
— carl.hiass