【问题标题】:Reproducing atoi() without external functions在没有外部函数的情况下重现 atoi()
【发布时间】:2018-03-03 11:59:59
【问题描述】:

我希望在不使用任何其他函数(例如 strtonum())的情况下重现 atoi() 函数的行为。我真的不明白如何将 charchar * 转换为 int 而不将其转换为 ASCII 值。我在 C 中做这个,有什么建议吗?

【问题讨论】:

  • 如果您的系统使用ASCII,那么char 元素中的字符已经 ASCII。对于数字,实际编码并不重要,因为 C 规范说所有数字 必须 是连续的,无论编码如何。根据该信息,并查看链接的 ASCII 表,您应该希望能够弄清楚如何获取例如1 来自'1'
  • 对十进制数系统有基本的了解也很好。
  • @Someprogrammerdude 不需要,因为所需的答案是转换整数值而不是浮点数或双精度值。
  • @AmazingThingsAroundYou 通过“十进制编号系统”我不是指浮点值,我是指数字如何基于10 以及如何将单个数字乘以(和除)10 .

标签: c char int data-conversion atoi


【解决方案1】:

哇,我好慢。很多人回答...顺便说一句,这是我的符号检测简单示例。如果遇到无效字符,则返回字符串的第一个解析部分:

#include <stdio.h>

int my_atoi(const char* input) {
  int accumulator = 0, // will contain the absolute value of the parsed number
      curr_val = 0, // the current digit parsed 
      sign = 1; // the sign of the returned number
  size_t i = 0; // an index for the iteration over the char array 

  // Let's check if there is a '-' in front of the number,
  // and change the final sign if it is '-'
  if (input[0] == '-') {
    sign = -1;
    i++;
  }
  // A '+' is also valid, but it will not change the value of
  // the sign. It is already +1!
  if (input[0] == '+')
    i++;

  // I think it is fair enough to iterate until we reach 
  // the null char...
  while (input[i] != '\0') {
    // The char variable has already a "numeric"
    // representation, and it is known that '0'-'9'                                 
    // are consecutive. Thus by subtracting the
    // "offset" '0' we are reconstructing a 0-9
    // number that is then casted to int.
    curr_val = (int)(input[i] - '0'); 

    // If atoi finds a char that cannot be converted to a numeric 0-9
    // it returns the value parsed in the first portion of the string.
    // (thanks to Iharob Al Asimi for pointing this out)
    if (curr_val < 0 || curr_val > 9)
      return accumulator;

    // Let's store the last value parsed in the accumulator,
    // after a shift of the accumulator itself.
    accumulator = accumulator * 10 + curr_val;
    i++;
  } 

  return sign * accumulator;
}


int main () {
   char test1[] = "234";
   char test2[] = "+6543";
   char test3[] = "-1234";
   char test4[] = "9B123";

   int a = my_atoi(test1);
   int b = my_atoi(test2);
   int c = my_atoi(test3);
   int d = my_atoi(test4);

   printf("%d, %d, %d, %d\n", a, b, c, d);
   return 0;
}

打印出来:

234, 6543, -1234, 9

【讨论】:

  • 非常感谢,帮了大忙。
  • 再问一个问题,请你解释一下“偏移量”'0',它是什么?
  • 如果我错了,请纠正我,但它是否基本上将 ascii 值更改为“input[i]”的 ascii 值 - '0' 的 ascii 值,以便该值介于 0 之间和 9 取决于 input[i] 的数字?
  • 让我们考虑 ASCII 值。字符 '5' 在 ASCII 表 53 中,而 '0' 是 48。这意味着 '5' - '0' = 53 - 48 = 5(这实际上是 char 'ENQ',但我们将其转换为 int 5 )
【解决方案2】:

考虑到您的系统使用ASCIIatoi 的实现类似于(请记住,该数字也可以是负数)

int catoi(const char *string)
{
    int res = 0;
    int sign = 1;
    if (*string == '-')
    {
        sign = -1;
        string++;
    }
    if (*string == '+') string++;

    while (*string >= '0' && *string <= '9')
    {
        res = res * 10 + (*string - '0')
        string++;
    }
    return (sign < 0) ? (-res) : res;
}

【讨论】:

  • 我不得不承认,相对于我的索引,您使用指针更优雅...
【解决方案3】:

尝试使用参考页面中的此代码:Write your own atoi()

// A simple C program for implementation of atoi
#include <stdio.h>

// A simple atoi() function
int PersonalA2I(char *str)
{
    int res = 0; // Initialize result

    // Iterate through all characters of input string and
    // update result
    for (int i = 0; str[i] != '\0'; ++i)
        res = res*10 + str[i] - '0';

    // return result.
    return res;
}

// Driver program to test above function
int main()
{
    char str[] = "123456";
    int val = PersonalA2I(str);
    printf ("%d ", val);
    return 0;
}

【讨论】:

  • 您可以编辑我的答案,而不是投票。如果我写 C 或 C++ 有什么区别.. 现在我将 C++ 更改为 C.. 运行它,输出将是相同的..
  • @IharobAlAsimi 否则不要带我去。我没有生你的气。我很抱歉。我必须感谢你让我意识到错误...谢谢。 :)
  • 谢谢!很有帮助!
【解决方案4】:

您可以转换charchar*如下:

int myAtoi(char *str)
{
    int dec = 0, i=0;

    for (i = 0; str[i] != '\0'; ++i)
        dec = dec*10 + str[i] - '0';
    return dec;
}

【讨论】:

    【解决方案5】:

    直接来自Brian W. Kernighan, Dennis M. Ritchie: The C Programming Language

    /* atoi: convert s to integer */
    int atoi(char s[])
    {
        int i, n;
        n = 0;
        for (i = 0; s[i] >= '0' && s[i] <= '9'; ++i)
        n = 10 * n + (s[i] - '0');
        return n;
    }
    

    【讨论】:

    • 支持,但引用这本书就像作弊......这不公平:)
    • 旧资源很糟糕,int atoi(char s[]) 将向非专家 程序员隐藏它与int atoi(char *s) 相同的事实,最终可能会错误地使用sizeof(s) .此外,就良好的设计而言,此函数应具有以下签名int atoi(const char *const string),最后将其称为atoi() 是不好的。
    • @MatteoRagni - 感谢您的支持。我同意你的看法,但为什么要重新发明轮子呢? 没有链接到源代码,假装它是我的代码会更不公平。
    • @MarianD 因为这个练习的目的是检查学生是否理解atoi() 在内部是如何工作的,所以它是给你的练习,而不是一个项目的任务,当然重新发明轮子意味着亏钱
    • @MarianD 对不起,我不能再为你的精彩评论投第二票了……即使你应得的:)
    【解决方案6】:

    另一个可用于长 ACSII 字符串的小字符串:

    #include <stdio.h> 
    
    long long int my_atoi(const char *c)
    {
        long long int value = 0;
        int sign = 1;
        if( *c == '+' || *c == '-' )
        {
            if( *c == '-' ) sign = -1;
            c++;
        }
        while (*c >= '0' && *c <= '9') // to detect digit == isdigit(*c))
        {
            value *= 10;
            value += (int) (*c-'0');
            c++;
        }
        return (value * sign);
    }
    
    int main () {
       char test1[] = "1234567890123456789";
       char test2[] = "+7654312345678901234";
       char test3[] = "-932112345678901234";
       char test4[] = "9A123123456789012";
    
       long long int a = my_atoi(test1);
       long long int b = my_atoi(test2);
       long long int c = my_atoi(test3);
       long long int d = my_atoi(test4);
    
       printf(" %lld\n %lld\n %lld\n %lld\n", a, b, c, d);
       return 0;
    }
    

    输出:

     1234567890123456789
     7654312345678901234
     -932112345678901234
     9
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2018-09-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-08-04
      • 2016-11-23
      • 2012-09-14
      • 2014-05-14
      相关资源
      最近更新 更多