I came across this question on SO, and this answer to the question. The code is as follows:
int main()
{
char u[10];
cout<<"Enter shape name ";
cin>>u;
if(u=="tri") //IS THIS UNDEFINED BEHAVIOR because the two decayed pointers both point to unrelated objects?
{
cout<<"everything is fine";
}
else
{
cout<<"Not fine";
}
return 0;
}
I have read in the mentioned answer that, both u
and "tri"
decay to pointers to their first element. My question is that, now is comparing these two decayed pointers undefined behavior because these pointers point to unrelated objects? Or the program is fine/valid(no UB) and because the pointers have different values, the else branch will be executed?
CodePudding user response:
Standard says:
[expr.eq]
The == (equal to) and the != (not equal to) operators group left-to-right. The lvalue-to-rvalue ([conv.lval]), array-to-pointer ([conv.array]), and function-to-pointer ([conv.func]) standard conversions are performed on the operands...
Hence, we are comparing pointers to the respective arrays.
If at least one of the operands is a pointer, ... Comparing pointers is defined as follows:
- If one pointer represents the address of a complete object, and another pointer represents the address one past the last element of a different complete object,72 the result of the comparison is unspecified. [does not apply since neither pointer is past last element]
- Otherwise, if the pointers are both null, both point to the same function, or both represent the same address, they compare equal. [does not apply since neither is null, neither point to functions, nor represent same address]
- Otherwise, the pointers compare unequal. [applies]
The behaviour is defined and else branch will be unconditionally executed.
Unconditionally unconditional if-statements imply that there is probably a bug; most likely the author was trying to compare the content of the arrays, which the operator does not do.
"warning: comparison with string literal results in unspecified behavior"
I believe that this warning message is slightly misleading. Comparison with two string literals would be unspecified:
if ("tri" == "tri")
It's unspecified whether this conditional is true or false.
CodePudding user response:
Comparing pointers via ==
is defined in compound#expr:
If at least one of the operands is a pointer, pointer conversions, function pointer conversions, and qualification conversions are performed on both operands to bring them to their composite pointer type. Comparing pointers is defined as follows:
(3.1) If one pointer represents the address of a complete object, and another pointer represents the address one past the last element of a different complete object, the result of the comparison is unspecified.
(3.2) Otherwise, if the pointers are both null, both point to the same function, or both represent the same address, they compare equal.
(3.3) Otherwise, the pointers compare unequal.
Neither of the pointers in your example represents the address one past the last element of a [different] complete object. Neither pointer is null. They do not represent the same address. Hence u=="tri"
is false.
Comparing pointers via <
is a different story, because there needs to be some ordering among the pointer values. To compare two pointers via ==
it only matters whether their value is the same or not.
CodePudding user response:
The code won't do what the author presumably wanted it to do, but there's no UB. While comparing pointers to unrelated objects with <
has unspecified results, checking equality is fine, and the comparison will produce false
.
CodePudding user response:
I don't think this is going to lead to undefined behavior but it definitely doesn't give correct results.
Using a debugger, look at the values you're comparing. For example if the input is "tri"
:
u == { 't','r','i','\0','\0','\0','\0','\0','\0','\0' }
"tri" == { 't','r','i','\0' }
..as you can see they're both different. Thus leading to their comparison resulting false
.
You can prove this by setting the size of u
to 4
(int u[4]
) and then giving the input "tri"
. You'll get the output
everything is fine
But this is not a flexible fix because it won't work with inputs >
or <
than 3
(or 4
by counting the null termination character \0
). To fix this issue, just convert your char array
into a std::string
:
#include<iostream>
#include<string>
int main()
{
char u[10]{};
std::cout << "Enter shape name ";
std::cin >> u;
if (std::string(u) == "tri") // Works fine now
{
std::cout << "everything is fine";
}
else
{
std::cout << "Not fine";
}
return 0;
}
..or maybe just use std::string
directly:
std::string u;
std::cout << "Enter shape name ";
std::cin >> u;
if (u == "tri")
{
// ...