Reputation: 79
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
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
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
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