Evaluating null terminated string [duplicate] - c++

This very simple code:
#include <iostream>
using namespace std;
void exec(char* option)
{
cout << "option is " << option << endl;
if (option == "foo")
cout << "option foo";
else if (option == "bar")
cout << "opzion bar";
else
cout << "???";
cout << endl;
}
int main()
{
char opt[] = "foo";
exec(opt);
return 0;
}
generate two warning: comparison with string literal results in unspecified behaviour.
Can you explain why exactly this code doesn't work, but if I change
char opt[]
to
char *opt
it works, but generates the warning? Is it related to the \0 termination? What is the difference between the two declaration of opt? What if I use const qualifier? The solution is to use std::string?

char arrays or char pointers aren't really the same thing as string class objects in C++, so this
if (option == "foo")
Doesn't compare the string option to the string literal "foo" it compares the address of option with the address of the string literal "foo". You need to use one of the many string comparison functions if you want to know if the option is the same as "foo". strcmp is the obvious way to do this, or you can use std::string instead of char*

You can use == operator to compare strings only if you use std::string (which is a good practice). If you use C-style char*/char[] strings, you need to use C functions strcmp or strncmp.
You can also use the std::string::operator == to compare std::string with a C string:
std string foo = "foo";
const char *bar = "bar";
if (foo == bar)
...

The reason why it doesn't work is because the comparison does not compare strings, but character pointers.
The reason why it may work when you use char* is because the compiler may decide to store the literal string "opt" once and reuse it for both references (I am sure I have seen a compiler setting somewhere that indicates whether the compiler does this).
In the case of char opt[], the compiler copies the string literal to the storage area reserved for the opt array (probably on the stack), which causes the pointers to be different.
Renze

For C++ I would use the std::string solution:
#include <iostream>
#include <string>
using namespace std;
void exec(string option)
{
cout << "option is " << option << endl;
if (option == "foo")
cout << "option foo";
else if (option == "bar")
cout << "option bar";
else
cout << "???";
cout << endl;
}
int main()
{
string opt = "foo";
exec(opt);
exec("bar");
char array[] = "other";
exec(array);
return 0;
}
std::string knows how to create itself out of char[], char*, etc, so you can still call the function in these ways, too.

Related

Concatenate a char into a string [duplicate]

im getting totally confused by this seemingly simple problem.
I have a pain old char, and I want to concatenate it in the middle of a string.
Like so.
string missingOptionArg(char missingArg) {
return "Option -" + missingArg + " requires an operand";
}
I was guessing the + operand was smart enough to deal with this sort of trivial thing, if not, what would be the simplest way of doing this?
To concatenate string literal and char:
std::string miString = std::string("something") + c;
A similar thing happens when you need to concat two strings literals.
Note that "something" is not a std::string, it is a pointer to an array of chars. Then you can't concatenate two string literals using +, that would be adding two pointers and is not what you want.
The correction of your code is in Igor's comment.
Accepted answer is the simplest but other ways to achieve the concatenation.
#include <iostream>
#include <string>
using namespace std;
string missingOptionArgRet(char missingArg) {
string s("Option -");
s += missingArg;
s += " requires an operand";
return s;
}
void missingOptionArgOut(char missingArg, std::string* out) {
*out = "Option -";
*out += missingArg;
*out += " requires an operand";
}
main(int, char**)
{
string s1 = missingOptionArgRet('x');
string s2;
missingOptionArgOut('x', &s2);
cout << "s1 = " << s1 << '\n';
cout << "s2 = " << s2 << '\n';
}
Using += rather than + will prevent temporary string objects. Also there are 2 options. Return by value missingOptionArgRet. This has disadvantage that as a result of return by value the string must be copied to the caller.
The second option missingOptionArgOut can prevent this at the cost of slightly more verbose code. I pass in an already constructed string (by pointer to make it clear its a variable to be modified, but could be passed by reference).

Issue regarding strrev() function in C++ language

I wrote a code to check if a string is a Palindrome or not. I assume logically my code is correct but the usage of strrev() function is incorrect. Please can anyone view it once? Thanks in advance
#include<iostream>
#include<string.h>
using namespace std;
int main(){
char name[100];
int result;
cout<<name<<endl;
result=strcmp(name,strrev(name));
if(result==0){
cout<<"YES";
}
else{
cout<<"NO";
}
return 0;
}
strrev is not a standard C function, so it is anyone's guess as to what it actually does. In case if it operates on the passed string in-place then the construction strcmp(name,strrev(name)) is wrong as it will always return 0 (the strings are equal). And, of course, the fact that you don't initialize name is also an error.
First off, name is not even initialized. It does not hold any string whatsoever, it holds garbage value. So you should first either take user input using cin >> name; or just explicitly initialize it at point of declaration using char name[100] = "yourString"
Secondly, strrev will reverse the given string before returning it. So when you do strcmp(name, strrev(name)). strrev(name) already reverses the actual name string before strcmp can execute. So you're always comparing the same strings. You should compare a copy of name instead.
Like so-
char name[100], temp[100];
std::cin >> name;
strcpy(temp, name);
Now you should be able to print the result like before-
if (result == 0)
{
std::cout << "YES\n";
}
else
{
std::cout << "NO\n";
}
Also, off topic but you don't have to explicitly store the result, you can directly compare the strcmp result like so -
if (!strcmp(name, _strrev(temp)))
{
std::cout << "YES\n";
}
else
{
std::cout << "NO\n";
}
Or you could use ternary operator -
std::cout << strcmp(name, _strrev(temp)) ? "NO\n" : "YES\n";
Here's the full program-
#include<iostream>
#include<string>
int main()
{
int result;
char name[100], temp[100];
std::cin >> name;
strcpy(temp, name);
std::cout << strcmp(name, _strrev(temp)) ? "NO\n" : "YES\n";
return 0;
}
Last but not the least, please consider not using strrev, it is a very old C standard function. You should use std::reverse instead and operate using std::string instead of C-Style strings. If you still want to keep using C style strings, use _strrev if that is available to you.
More info on C and C++ style strings

Trying to check entered text versus my own custom answers

here is what I attempted to throw together, unfortunately it's not doing what I want it to. What I want it to be doing is checking the entered text vs a few words that I consider correct. So, for example, if I want the only correct answers to be "thanks" or "please", how would I make the program check if the word the user entered is either "thanks" or "please"?
I have a feeling I can't just write B == 'funs etc.
help me out please:
#include <iostream>
using namespace std;
int main ()
{
string B;
for (;;)
{cout << "enter text here" << '\n' ;
cin >> B ;
if (B == 'fUNS'|| B == 'funs' || B == 'funzies')
{
cout << "correct!!!!!!" << endl;
break;
}
else
{
cout << "sorry, please try again" << endl;
continue;
}
}
return 0;
}
Unlike some languages using ' or " to enclose a sequence of characters produces very different results.
A single quote defines a single character literal e.g:
char a = 'A';
You can use multiple characters to define the value of an integer (although this is non-standard):
int a = 'ABCD';
A double quote defines a string literal which is a sequence of characters in an array:
const char str[5] = "ABCD";
Note the literal has a hidden null character at the end which is why it has 5 elements rather than 4. String literals are comparable and assignable with std::string:
std::string test( "ABCD" );
std::cout << test == "ABCD";
test = "EFGH";
std::cout << test == "ABCD";
I have a feeling I can't just write B == 'funs etc.
Yes, you can, since B is a std::string, which has an operator== defined. You just need to use " (which is used to define string literals) instead of ' (which is used to define character literals), eg:
if (B == "fUNS" || B == "funs" || B == "funzies")

Concatenate plain char and string?

im getting totally confused by this seemingly simple problem.
I have a pain old char, and I want to concatenate it in the middle of a string.
Like so.
string missingOptionArg(char missingArg) {
return "Option -" + missingArg + " requires an operand";
}
I was guessing the + operand was smart enough to deal with this sort of trivial thing, if not, what would be the simplest way of doing this?
To concatenate string literal and char:
std::string miString = std::string("something") + c;
A similar thing happens when you need to concat two strings literals.
Note that "something" is not a std::string, it is a pointer to an array of chars. Then you can't concatenate two string literals using +, that would be adding two pointers and is not what you want.
The correction of your code is in Igor's comment.
Accepted answer is the simplest but other ways to achieve the concatenation.
#include <iostream>
#include <string>
using namespace std;
string missingOptionArgRet(char missingArg) {
string s("Option -");
s += missingArg;
s += " requires an operand";
return s;
}
void missingOptionArgOut(char missingArg, std::string* out) {
*out = "Option -";
*out += missingArg;
*out += " requires an operand";
}
main(int, char**)
{
string s1 = missingOptionArgRet('x');
string s2;
missingOptionArgOut('x', &s2);
cout << "s1 = " << s1 << '\n';
cout << "s2 = " << s2 << '\n';
}
Using += rather than + will prevent temporary string objects. Also there are 2 options. Return by value missingOptionArgRet. This has disadvantage that as a result of return by value the string must be copied to the caller.
The second option missingOptionArgOut can prevent this at the cost of slightly more verbose code. I pass in an already constructed string (by pointer to make it clear its a variable to be modified, but could be passed by reference).

comparison between string literal

This very simple code:
#include <iostream>
using namespace std;
void exec(char* option)
{
cout << "option is " << option << endl;
if (option == "foo")
cout << "option foo";
else if (option == "bar")
cout << "opzion bar";
else
cout << "???";
cout << endl;
}
int main()
{
char opt[] = "foo";
exec(opt);
return 0;
}
generate two warning: comparison with string literal results in unspecified behaviour.
Can you explain why exactly this code doesn't work, but if I change
char opt[]
to
char *opt
it works, but generates the warning? Is it related to the \0 termination? What is the difference between the two declaration of opt? What if I use const qualifier? The solution is to use std::string?
char arrays or char pointers aren't really the same thing as string class objects in C++, so this
if (option == "foo")
Doesn't compare the string option to the string literal "foo" it compares the address of option with the address of the string literal "foo". You need to use one of the many string comparison functions if you want to know if the option is the same as "foo". strcmp is the obvious way to do this, or you can use std::string instead of char*
You can use == operator to compare strings only if you use std::string (which is a good practice). If you use C-style char*/char[] strings, you need to use C functions strcmp or strncmp.
You can also use the std::string::operator == to compare std::string with a C string:
std string foo = "foo";
const char *bar = "bar";
if (foo == bar)
...
The reason why it doesn't work is because the comparison does not compare strings, but character pointers.
The reason why it may work when you use char* is because the compiler may decide to store the literal string "opt" once and reuse it for both references (I am sure I have seen a compiler setting somewhere that indicates whether the compiler does this).
In the case of char opt[], the compiler copies the string literal to the storage area reserved for the opt array (probably on the stack), which causes the pointers to be different.
Renze
For C++ I would use the std::string solution:
#include <iostream>
#include <string>
using namespace std;
void exec(string option)
{
cout << "option is " << option << endl;
if (option == "foo")
cout << "option foo";
else if (option == "bar")
cout << "option bar";
else
cout << "???";
cout << endl;
}
int main()
{
string opt = "foo";
exec(opt);
exec("bar");
char array[] = "other";
exec(array);
return 0;
}
std::string knows how to create itself out of char[], char*, etc, so you can still call the function in these ways, too.