【问题标题】:Custom strtoi function compile time issue自定义 strtoi 函数编译时问题
【发布时间】:2020-02-28 08:35:54
【问题描述】:

我正在尝试实现一个非常简单的strtoi 函数。当动态创建传递的参数时它工作正常(下面的案例 2)。但是,如果 char 是由在编译时分配的 char[] 创建的,我会在 len 上得到一个常量值,因为 std::strlen(ch) 会扰乱我的逻辑,我找不到解决方案。

 int strtoi(char* ch)
 {   
  int sum {0};
  int len = static_cast<int>(std::strlen(ch));
  int skipLast = static_cast<int>(static_cast<int>(ch[0]) == 45);

  //Integer Method
  for(int i = len - 1; i >= 0 + skipLast; i--)
  {
    if(static_cast<int>(ch[i]) < 48 || static_cast<int>(ch[i]) > 57)
      return 0;
    sum += (ch[i]-48) * std::pow(10,i-skipLast);
  }

   sum = skipLast == 1 ? -sum : sum;
   return sum;
 }

int main()
{
  char pos[3] {'1','2','3'};
  std::cout << strtoi(pos) << std::endl;
  char neg[4] {'-','1','2','3'};
  std::cout << strtoi(neg) << std::endl;
  return 0;
}

返回:0-123。我的函数中的len 变量在第一次调用时没有得到预期值,我认为这是因为neg[4] 分配了比pos[3] 更多的内存。但是,对于第二种情况:

int main()
{
  char* pos;
  pos = new char[3] {'1','2','3'};
  std::cout << strtoi(pos) << std::endl;
  char* neg;
  neg = new char[4] {'-','1','2','3'};
  std::cout << strtoi(neg) << std::endl;
  return 0;
}

返回123-123。预期的结果。 我猜这是因为在第一种情况下,编译器根据char[4] 数组为函数及其参数分配内存。它是否正确? 对于第二种情况,它是如何工作的,编译器如何为动态变量的函数分配内存? 使该功能适用​​于两种情况的可能解决方案是什么? 提前感谢您的帮助。

【问题讨论】:

  • static_cast&lt;int&gt;(static_cast&lt;int&gt;(ch[0]) == 45)ch[0] == '-' 的一种非常复杂的说法。我还建议您学习改用std::isdigitch[i]-'0'。并且一般停止使用magic numbers
  • 还要注意std::pow是一个浮点函数,它带来了处理浮点值的所有问题(如舍入错误)。还有其他方法可以使用 10 个装扮者,例如通过适当地初始化一个整数变量,然后在循环的每次迭代中将其乘以或除以 10

标签: c++ c++11 compile-time-constant


【解决方案1】:

strlen 要求字符串以 null 结尾,如下所示:

char* pos = new char[4] {'1','2','3','\0'};
std::cout << strlen(pos) << "\n";  // Shows "3"

添加这个空终止符有一个简写:

const char[] pos = "123";
std::cout << strlen(pos) << "\n";  // Shows "3"
std::cout << sizeof(pot) << "\n";  // Shows "4"

我使用数组类型来表示 pos 只是为了说明它实际上是 4 个字符;您可以改用const char*(实际上这是典型的),但是sizeof 行将不起作用。

请注意,如果您分配这样的字符串文字,则以后不能在其上使用delete,而如果您使用new,则可以(并且应该)使用delete,或者对于数组使用delete[]

【讨论】:

  • char* pos = new char[3] {'1','2','3','\0'}; 不正确。
  • @anastaciu 你是对的,感谢您指出这一点。我已经编辑了我的答案。
【解决方案2】:

您遇到的问题是您忘记了 C++ 中的 char 字符串实际上称为 null-terminated 字节字符串。

null-terminator 是所有标准字符串函数(如std::strlen)都会查找的内容,以了解字符串的结束位置。

您的字符串是 not 以空值结尾的,因此将它们传递给例如std::strlen 将导致 undefined behavior 超出数组或分配的内存范围,寻找这个不存在的空终止符。

要解决这个问题,您需要确保所有字符串都以 null 结尾:

// will create pos as an array of *four* characters, the last being the null-terminator
char pos[] = "123";

【讨论】:

    【解决方案3】:

    我已将您的代码修改如下:

    int strtoi(char* ch, int len)
    {
        int sum{ 0 };
        //int len = (std::strlen(ch));
        int skipLast = static_cast<int>(static_cast<int>(ch[0]) == 45);
    
        //Integer Method
        for (int i = len - 1; i >= 0 + skipLast; i--)
        {
            if (static_cast<int>(ch[i]) < 48 || static_cast<int>(ch[i]) > 57)
                return 0;
            sum += (ch[i] - 48) * std::pow(10, i - skipLast);
        }
    
        sum = skipLast == 1 ? -sum : sum;
        return sum;
    }
    
    int main()
    {
        char pos[3]{ '1','2','3' };
        std::cout << strtoi(pos, 3) << std::endl;
        char neg[4]{ '-','1','2','3' };
        std::cout << strtoi(neg, 4) << std::endl;
        return 0;
    }
    

    strtoi 无法计算函数内的数组长度。您必须使用数组指针传递它,因为没有 '\0' 字符。 这就是为什么当你将数组传递给函数时,你也必须传递数组的大小或长度。

    以上修改代码的输出:

    321

    -321

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-04-04
      • 1970-01-01
      相关资源
      最近更新 更多