Пользовательская функция strtoi проблема времени компиляции - PullRequest
1 голос
/ 28 февраля 2020

Я пытаюсь реализовать очень простую strtoi функцию. Он прекрасно работает, когда переданные аргументы создаются динамически (случай 2 ниже). Однако, если символ создается с помощью char[], который выделяется во время компиляции, я получаю постоянное значение на len из-за std::strlen(ch), которое портит мои логики c, и я не могу найти решение для это.

 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]. Это правильно? Как это работает во втором случае, как компилятор выделяет память функции для динамических переменных c? И какое возможное решение заставить функцию работать в обоих случаях? Заранее спасибо за любую помощь.

Ответы [ 3 ]

5 голосов
/ 28 февраля 2020

strlen требует, чтобы строка завершилась нулем, например:

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 в позже, тогда как вы можете (и должны) использовать delete, если используете new или delete[] для массивов.

3 голосов
/ 28 февраля 2020

Я изменил ваш код, как показано ниже:

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

3 голосов
/ 28 февраля 2020

Проблемы, с которыми вы столкнулись, заключаются в том, что вы забыли, что char строки в C ++ действительно называются строки с нулевым символом в конце строки байтов .

Это null -terminator - это то, что все стандартные строковые функции (например, std::strlen) будут искать, чтобы узнать, где заканчивается строка.

Ваши строки не заканчиваются нулем, поэтому их передают Например, std::strlen приведет к неопределенному поведению , поскольку они go выходят за пределы массивов или выделенной памяти, ища этот несуществующий нулевой терминатор.

Чтобы решить эту проблему, вам нужно убедиться, что все строки заканчиваются нулем:

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