11

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] = '\0';
    while (n) {
        len--;
        s[len - 1] = (n % 10) + '0';
        n /= 10;
    }
    return (s);
}
4

7 に答える 7

10

この行:

if (x == -2147483648)

あなたが思っていることをしません。C には負の整数定数はありません。これは、値が 2^31 の unsigned int 定数で、単項マイナス演算子を適用します。これは、式x == -21...がコンパイラが使用する C 標準に依存することを意味します。

C99やC11を使えば大丈夫です。十分な大きさの符号付き型があります - long long はこの数値に対して十分な大きさであることが保証されているため、x と -21... の両方が long long に変換されてから比較されます。ただし、C89 コンパイラを使用していて、マシンに十分な長さの型がない場合は、ここで実装定義の動作にヒットしています。

整数がより小さいサイズの符号付き整数に降格されるか、符号なし整数が対応する符号付き整数に変換される場合、値を表すことができない場合、結果は実装定義です。

これが、人々が limits.h を使用するように言っている理由です。彼らが衒学的であるからではなく、これが危険な領域だからです. limits.h の内容をよく見ると、次のような行が見つかる可能性が高くなります。

#define INT_MIN (- INT_MAX - 1)

この式は、実際には正しい型と値を持っています。

それ以外は、投稿したコードにエラーは見られません。これが問題ではないかft_intlenft_strdup間違っている場合。または、テストで間違った関数を呼び出しています (テストを呼び出すときに同じ問題が -21 に適用されます)。

于 2016-10-10T13:45:54.853 に答える
2

ステータス: 解決済み 無効

理由: WORKS_FOR_ME

とにかく、いくつかの点で改善しました。

  • sizeof(char)は常に 1 です。その必要はありません。
  • キャストしないでくださいmalloc
  • 特殊なケース 0 を処理する場合は、一度に処理してください。
  • -2147483648非常に悪いです。それINT_MINがそのためです。
  • return は関数ではありません。 return を使用しないで(value)くださいvalue
  • s[len - 1]常にではなくlen、ループに入る前にデクリメントすることをお勧めします。または、呼び出しでlen + 1のみ必要なため、as を返して、を使用して呼び出すだけですmalloclenintlenmalloclen + 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] = '\0';
        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]\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
于 2016-10-08T08:25:51.550 に答える
2

そのチェックは必要ありません。代わりに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] = '\0';
    if (negative)
        s[0] = '-';
    do {
        s[--len] = (n % 10) + '0';
        n /= 10;
    } while(n);
    return (s);
}

size_t ft_uintlen(unsigned)これは、引数で機能する新しい関数を使用することに注意してunsignedください。

于 2016-10-10T22:02:40.073 に答える
0

使用するだけです:

INT_MIN

それ以外の:

-2147483648

あなたのテストで:

if (x == INT_MIN)
    return (ft_strdup("-2147483648"));

その理由は、一部のコンパイラではその数を理解するのに問題がある可能性があるためです。

標準 C ライブラリのlimits.hでは通常、次のように定義されています。

#define INT_MIN  (-INT_MAX - 1)

この問題を回避するために。

于 2016-10-17T09:10:51.873 に答える
0

あなたがコンパイルしてOsXで動作するコードの一部ですが、私自身ft_stdupft_intlen. そのため、コードを表示するか、エラーがないか確認してください。いくつかのテストを行いました (2147483647、-2147483648 を含む)。それはうまく機能します。

とにかく、行:

if (x == -2147483648) return (ft_strdup("-2147483648"));

なんらかの操作を行う前にx値をlong long変数(Art )にコピーする限り、役に立ちません。したがって、含める必要はありませんtypes.h(悪名高いムーリネットは-42を与えません)。

OsX ではlong値に対しても機能することがありますが、これは移植性が高くありません。

于 2016-10-14T12:47:44.517 に答える
0

潜在的なコード エラー (疑わしい順):

  1. ft_strdup()そのコードは「int min value」で呼び出され、エラーが発生するためです。
  2. さまざまな機能が欠けているプロトタイプ。特にft_strdup()/strdup()
  3. 呼び出し/テスト コードに問題があります。
  4. "int min value" が -2147483648 より大きい。( を使用することをお勧めしますINT_MIN。)
  5. ft_intlen(n)が正しくコーディングされず、 が返さINT_MAXれた後、コードが を試行しmalloc(INT_MIN)ます。
  6. int/long両方とも 64 ビット。これは最初のものを台無しにs[len - 1] = (n % 10) + '0';INT_MINます。

それ以外の場合INT_MIN、値が -2147483648であれば問題ありませんft_itoa(int x)


OPは「... strdupは文字列を割り当てるだけで、ft_intlenは文字列の長さを返すだけで、両方ともテストケースに合格します – franklinexpress 10月8日7時52分」

テスト ケースに合格しても、未定義の動作を呼び出さずに機能したとは限りません。投稿しft_intlen()ft_strdup()レビュー用にハーネスをテストするのが最善です。


ポータブル実装の候補。int/longサイズや 2 の補数に依存しません。あまりにも多くの可搬性を犠牲にすることなく、コードが 8 であると仮定できる<limits.h>ことを除けば、必要はありません。C89/99/11 で動作します。CHAR_BIT

// Buffer size needed to decimal print any `int`
// '-' + Ceiling(value bit size * log10(2)) + \0
#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 = '\0';

  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); 
}
于 2016-10-13T17:49:56.247 に答える