27

次のatoi実装コード、特にこの行を理解できません。

k = (k << 3) + (k << 1) + (*p) - '0';

コードは次のとおりです。

int my_atoi(char *p) {
    int k = 0;
    while (*p) {
        k = (k << 3) + (k << 1) + (*p) - '0';
        p++;
     }
     return k;
}

誰かが私にそれを説明できますか?

atof別の質問:実装のアルゴリズムはどうあるべきですか?

4

6 に答える 6

33

<<はビット シフト(k<<3)+(k<<1)ですk*10。コンパイラよりも賢いと思っていた人によって書かれました (まあ、彼は間違っていました...)。

(*p) - '0'0が指す文字から文字の値を減算し、文字を数値pに効果的に変換します。

残りを理解していただければ幸いです... 10進法がどのように機能するかを覚えておいてください。

以下は標準機能の仕様ですatoi。標準を引用せずに申し訳ありませんが、これは問題なく機能します(http://www.cplusplus.com/reference/clibrary/cstdlib/atoi/から)

isspaceこの関数は、最初の非空白文字が見つかるまで、必要な数の空白文字 ( のように) を最初に破棄し ます。次に、この文字から始めて、オプションの最初のプラス記号またはマイナス記号と、それに続く 10 進数の可能な限り多くの数字を取り、それらを数値として解釈します。

文字列には、整数を形成する文字の後に追加の文字を含めることができます。これらの文字は無視され、この関数の動作には影響しません。

の非空白文字の最初のシーケンスがstr有効な整数でない場合、または strが空であるか、空白文字のみが含まれているためにそのようなシーケンスが存在しない場合、変換は実行されず、0 が返されます。

于 2012-10-08T23:59:06.317 に答える
31
k = (k << 3) + (k << 1);

意味

k = k * 2³ + k * 2¹ = k * 8 + k * 2 = k * 10

それは役に立ちますか?

項は次の桁の*p - '0'値を加算します。これが機能するのは、C では数字文字に連続した値が必要なため'1' == '0' + 1'2' == '0' + 2、 などです。

2 番目の質問 ( atof) については、それは独自の質問である必要があり、論文の主題であり、簡単に答えられるものではありません...

于 2012-10-08T23:58:51.140 に答える
1
#include <stdio.h>
#include <errno.h>
#include <limits.h>

double atof(const char *string);

int debug=1;

int main(int argc, char **argv)
{
    char *str1="3.14159",*str2="3",*str3="0.707106",*str4="-5.2";
    double f1,f2,f3,f4;
    if (debug) printf("convert %s, %s, %s, %s\n",str1,str2,str3,str4);
    f1=atof(str1);
    f2=atof(str2);
    f3=atof(str3);
    f4=atof(str4);

    if (debug) printf("converted values=%f, %f, %f, %f\n",f1,f2,f3,f4);
    if (argc > 1)
    {
        printf("string %s is floating point %f\n",argv[1],atof(argv[1]));
    }
}

double atof(const char *string)
{
    double result=0.0;
    double multiplier=1;
    double divisor=1.0;
    int integer_portion=0;

    if (!string) return result;
    integer_portion=atoi(string);

    result = (double)integer_portion;
    if (debug) printf("so far %s looks like %f\n",string,result);

    /* capture whether string is negative, don't use "result" as it could be 0 */
    if (*string == '-')
    {
        result *= -1; /* won't care if it was 0 in integer portion */
        multiplier = -1;
    }

    while (*string && (*string != '.'))
    {
        string++;
    }
    if (debug) printf("fractional part=%s\n",string);

    // if we haven't hit end of string, go past the decimal point
    if (*string)
    {
        string++;
        if (debug) printf("first char after decimal=%c\n",*string);
    }

    while (*string)
    {
        if (*string < '0' || *string > '9') return result;
        divisor *= 10.0;
        result += (double)(*string - '0')/divisor;
        if (debug) printf("result so far=%f\n",result);
        string++;
    }
    return result*multiplier;
}
于 2012-12-24T06:13:08.443 に答える
0

興味深いことに、atoi のマニュアル ページには errno の設定が示されていません。そのため、(2^31)-1 を超える任意の数を話している場合は不運であり、-2^31 未満の数についても同様です (32 と仮定すると-ビット整数)。答えは返ってきますが、それはあなたが望むものではありません。これは、-((2^31)-1) から (2^31)-1 の範囲を取り、エラーの場合は INT_MIN (-(2^31)) を返すものです。次に、errno をチェックして、オーバーフローしたかどうかを確認できます。

#include <stdio.h>
#include <errno.h>  /* for errno */
#include <limits.h> /* for INT_MIN */
#include <string.h> /* for strerror */

extern int errno;

int debug=0;
int atoi(const char *c)
{
    int previous_result=0, result=0;
    int multiplier=1;

    if (debug) printf("converting %s to integer\n",c?c:"");
    if (c && *c == '-')
    {
        multiplier = -1;
        c++;
    }
    else
    {
        multiplier = 1;
    }
    if (debug) printf("multiplier = %d\n",multiplier);
    while (*c)
    {
        if (*c < '0' || *c > '9')
        {
            return result * multiplier;
        }
        result *= 10;
        if (result < previous_result)
        {
            if (debug) printf("number overflowed - return INT_MIN, errno=%d\n",errno);
            errno = EOVERFLOW;
            return(INT_MIN);
        }
        else
        {
            previous_result *= 10;
        }
        if (debug) printf("%c\n",*c);
        result += *c - '0';

        if (result < previous_result)
        {
            if (debug) printf("number overflowed - return MIN_INT\n");
            errno = EOVERFLOW;
            return(INT_MIN);
        }
        else
        {
            previous_result += *c - '0';
        }
        c++;
    }
    return(result * multiplier);
}

int main(int argc,char **argv)
{
    int result;
    printf("INT_MIN=%d will be output when number too high or too low, and errno set\n",INT_MIN);
    printf("string=%s, int=%d\n","563",atoi("563"));
    printf("string=%s, int=%d\n","-563",atoi("-563"));
    printf("string=%s, int=%d\n","-5a3",atoi("-5a3"));
    if (argc > 1)
    {
        result=atoi(argv[1]);
        printf("atoi(%s)=%d %s",argv[1],result,(result==INT_MIN)?", errno=":"",errno,strerror(errno));
        if (errno) printf("%d - %s\n",errno,strerror(errno));
        else printf("\n");
    }
    return(errno);
}
于 2012-12-24T04:04:07.937 に答える