itoa () C реализация int min underflow
Я запускаю некоторые тестовые случаи против моей функции itoa (), но продолжаю получать
did not allocate memory for the int min value
Я делаю проверку, но это то, что я пропустил здесь, что это?
char *ft_itoa(int x) {
    char *s;
    size_t len;
    long int n;
    n = x;
    if (x == -2147483648)
        return (ft_strdup("-2147483648"));
    len = ft_intlen(n) + 1;
    if (!(s = (char*)malloc(sizeof(char) * len)))
        return (NULL);
    if (n == 0)
        s[0] = '0';
    if (n < 0) {
        s[0] = '-';
        n = -n;
    }
    s[len - 1] = '';
    while (n) {
        len--;
        s[len - 1] = (n % 10) + '0';
        n /= 10;
    }
    return (s);
}
            7 ответов
эта строка:
if (x == -2147483648)
не делать то, что вы думаете. C не имеет отрицательных целочисленных констант. Это беззнаковая константа int со значением 2^31, к которой применяется унарный оператор минус. Это означает, что выражение x == -21... будет зависеть от стандарта C компилятор использует.
если вы используете C99 или C11, вы будете в порядке. Существует подписанный тип, который достаточно большой-long long гарантированно будет достаточно большим для этого числа, поэтому как x, так и -21... будет преобразован в long long, а затем сравнивается. Но если вы используете компилятор C89, и у вашей машины недостаточно длинный тип, вы нажимаете поведение, определяемое реализацией:
когда целое число понижается до целого со знаком меньшего размера или целое без знака преобразуется в соответствующее целое со знаком, если значение не может быть представлено, результат определяется реализацией.
вот почему люди говорят, чтобы использовать пределы.h. Не потому, что они педантичны, а потому, что это опасная территория. Если присмотреться, какие пределы.h содержит, вы, скорее всего, найдете такую строку:
#define INT_MIN (- INT_MAX - 1)
Это выражение на самом деле имеет правильный тип и значение.
кроме того, я не вижу никаких ошибок в коде вас в курсе. Если это не проблема ft_intlen или ft_strdup ошибаетесь. Или вы вызываете свою функцию при тестировании неправильно (те же проблемы применяются к -21... когда вызов тестов).
статус: RESOLVED недопустимый
причина: WORKS_FOR_ME
в любом случае, я улучшил некоторые моменты.
- 
sizeof(char)всегда 1, нет необходимости в этом. - не бросайте 
malloc - если вы обрабатываете специальный случай 0, то просто обработайте его за один раз.
 - 
-2147483648очень очень плохо. Вот что!--6--> для. - return не является функцией, не возвращайте 
(value), просто вернутьсяvalue. - не 
s[len - 1]все время, лучше декрементыlenперед входом в цикл. Или, так как вам нужноlen + 1только вmallocзвонок, простоlenasintlenвозвращает его и называютmallocиспользуяlen + 1 
ft_itoa.c
#include <stdbool.h>
#include <limits.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <btstr.h>
int ft_intlen(int n) {
        char buffer[8192];
        return snprintf(buffer, sizeof buffer, "%i", n);
}
char * ft_itoa(int n) {
        char * s;
        size_t l, len;
        bool fix_int_min = false;
        if (!n) {
                return mstrcpy("0");
        }
        if (-INT_MAX != INT_MIN && n == INT_MIN) {
                ++n;
                fix_int_min = true;
        }
        len = ft_intlen(n);
        if (!(s = malloc(len + 1))) {
                return NULL;
        }
        if (n < 0) {
                s[0] = '-';
                n = -n;
        }
        s[l = len] = '';
        while (n) {
                s[--len] = (n % 10) + '0';
                n /= 10;
        }
        if (fix_int_min) {
                --l;
                while (s[l] == '9') {
                        s[l++] = 0;
                }
                if (s[l] == '-') {
                        // realloc +1 and write "-1[0....0]"
                } else {
                        ++s[l];
                }
        }
        return s;
}
main.c
#include <limits.h>
#include <stdio.h>
char * ft_itoa(int n);
void check(int n) {
        printf("%i = %s\n", n, ft_itoa(n));
}
int main() {
        check(0);
        check(-1);
        check(1);
        check(23);
        check(42);
        check(4711);
        check(1000);
        check(INT_MAX);
        check(1+INT_MIN);
        check(INT_MIN);
}
результат
$ gcc -W -Wall -Wextra -lBtLinuxLibrary ft_itoa.c main.c -o ft_itoa && ./ft_itoa
0 = 0
-1 = -1
1 = 1
23 = 23
42 = 42
4711 = 4711
1000 = 1000
2147483647 = 2147483647
-2147483647 = -2147483647
-2147483648 = -2147483648
вам не нужен чек. Вместо этого преобразуйте его в unsigned, что будет соответствовать абсолютному значению :
size_t ft_uintlen(unsigned n)
{
    size_t len = 0;
    do {
        ++len;
        n /= 10;
    } while(n);
    return len;
}
char *ft_itoa(int x)
{
    char    *s;
    size_t  len;
    unsigned n;
    int negative;
    negative = x < 0;
    n = negative ? 0-(unsigned)x : (unsigned)x;
    len = ft_uintlen(n) + negative + 1;
    if (!(s = (char*)malloc(len)))
        return (NULL);
    s[--len] = '';
    if (negative)
        s[0] = '-';
    do {
        s[--len] = (n % 10) + '0';
        n /= 10;
    } while(n);
    return (s);
}
обратите внимание, что это использует новый size_t ft_uintlen(unsigned) функция, которая работает на unsigned аргументов.
вероятно, проблема в вашем механизме предотвращения переполнения. Вы пытаетесь назначить x типа int to n С типом long int. Но спецификация не гарантирует этот тип long int смогите отрегулировать ряд значения большой после этого int. Более подробную информацию можно найти  " Long Vs. Int". 
использовать long long int тип n если ваш компилятор поддерживает его. Обновите свой 
потенциальные сбои кода, в порядке подозрения:
- 
ft_strdup()поскольку этот код вызывается с "int min value" и возникает ошибка. -  прототипы, отсутствующие для различных функций.  Особенно 
ft_strdup()/strdup(). - вызов / тестовый код неисправен.
 -  "int min value" больше, чем -2147483648.  (Лучше использовать 
INT_MIN.) - 
ft_intlen(n)неправильно закодирован и возвращаетINT_MAX, то код пытаетсяmalloc(INT_MIN). - 
int/long64-разрядная. Это беспорядок первыйs[len - 1] = (n % 10) + '0';СINT_MIN. 
в противном случае, если INT_MIN имеет значение -2147483648, ft_itoa(int x) - это хорошо.
OP утверждает "... strdup просто выделяет строку, ft_intlen просто возвращает длину строки, оба проходят тестовые случаи-franklinexpress Oct 8 в 7: 52"
прохождение тестовых случаев не означает, что он работал без вызова неопределенного поведения.  Лучше всего разместить ft_intlen(), ft_strdup() и теста для обзора.
кандидат портативный реализация.  Не зависит int/long размер или дополнение 2.  Нет необходимости <limits.h> помимо CHAR_BIT какой код  мог бы предположим, что это 8, не жертвуя слишком много питьевой.  Работает с C89/99/11.
// Buffer size needed to decimal print any `int`
// '-' + Ceiling(value bit size * log10(2)) + 
#define INT_STR_SIZE (1 + ((CHAR_BIT*sizeof(int) - 1)/3 + 1) + 1)
char *ft_itoa(int x) {
  char buf[INT_STR_SIZE];
  char *s = buf + sizeof buf - 1;  // Set to end of buffer
  *s = '';
  int n = x; // no need for wider types like long
  if (n > 0) {
    // fold positive numbers to negative ones
    // This avoids the special code for `INT_MIN` and need for wider types
    n = -n;
  }
  // Using a do loop avoids special code for `x==0`
  do {
    // Use `div()` rather than / % in case we are using C89.
    // / %  has implementation defined results for negative arguments.
    div_t qr = div(n, 10);
    *--s = (char) ('0' - qr.rem);  // Form digit from negative .rem
    n = qr.quot;
  } while (n);
  if (x < 0) {
    *--s = '-';
  }
  // Double check ft_strdup() is coded correctly
  // Insure calling code frees the buffer when done.
  return ft_strdup(s); 
}
кусок кода, который вы дали, компилируется и работает на OsX, но с моим собственным ft_stdup и ft_intlen. Таким образом, вы можете либо показать нам код, либо проверить их на наличие ошибок.
Я сделал несколько тестов (в том числе 2147483647, -2147483648). Это прекрасно работает.
во всяком случае, строки:
if (x == -2147483648)
    return (ft_strdup("-2147483648"));
бесполезны, пока вы копируете свой x стоимостью в long long переменной (искусство) перед делать любой вид деятельности оно. Так что вам не нужно включать types.h (пресловутый moulinette не даст вам -42).
бывает, что на OsX он работает и на long значения, но это не портативный безопасный.
просто использовать:
INT_MIN
вместо:
-2147483648
в вашем тесте:
if (x == INT_MIN)
    return (ft_strdup("-2147483648"));
причина этого в том, что некоторые компиляторы могут иметь проблемы с пониманием этого числа.
стандартная библиотека C ограничения.h обычно определяют его как:
#define INT_MIN  (-INT_MAX - 1)
чтобы избежать этой проблемы.