Scheir
Scheir

Reputation: 79

Custom strtoi function compile time issue

I am trying to implement a very simple strtoi function. It works fine when when the passed arguments are dynamically created (case 2 below). However, if the char is created by char[] which is allocated during compile time, I get a constant value on len because of std::strlen(ch) which messes up my logic, and I can't find a solution for this.

 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;
}

Returns: 0 and -123. The len variable in my function doesn't get the expected value for the first call and I assume it is because neg[4] allocates more memory then pos[3]. However, for the second case:

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;
}

Returns 123, -123. The expected result. I guess this happens because in the first case the compiler is allocating memory for the function and its argument according to the char[4] array. Is this correct? How does it works for the second case, how is the compiler allocating memory to the function for the dynamic variables? And what is a possible solution to make the function work for both cases? Thanks in advance for any help.

Upvotes: 1

Views: 105

Answers (3)

Arthur Tacca
Arthur Tacca

Reputation: 10018

strlen requires that the string be null terminated, like this:

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

There is a short hand for adding this null terminator:

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

I used an array type for pos just to illustrate it is really 4 characters; you could use const char* instead (actually that would be typical) but then the sizeof line wouldn't work.

Note that if you allocate a string literal like this then you cannot use delete on it later, whereas you can (and should) use delete if you use new, or delete[] for arrays.

Upvotes: 5

Build Succeeded
Build Succeeded

Reputation: 1150

I have modified your code as below:

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 was not able to calculate the array length inside a function. You have to pass it with an array pointer as there is no '\0' character. That's why when you pass an array to function you have to pass the array size or length as well.

Output of above-modified code:

321

-321

Upvotes: 3

Some programmer dude
Some programmer dude

Reputation: 409404

The problems you have is that you forget that char strings in C++ are really called null-terminated byte strings.

That null-terminator is what all standard string functions (like std::strlen) will look for to know where the string ends.

Your strings are not null-terminated, therefore passing them to e.g. std::strlen will lead to undefined behavior as they go out of bounds of the arrays or allocated memory, looking for this non-existing null-terminator.

To solve that problem you need to make sure that all strings are null-terminated:

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

Upvotes: 3

Related Questions