I am just messing around in C++ with some things I recently learned and I wanted to know how to correctly compare two strings to each other. I looked at a previous thread for help, but I am not sure I am getting the variables right and there was a repeating error. (P.S. This is executed to the command prompt.)
string Users = "Username1";
//Set an empty string.
string UserChoice;
//Print out a line that warns the user to type a user.
std::cout << "Username: ";
std::cin >> UserChoice;
//If the user types out whatever "Users" is, run the code below.
if (strcmp(Users, UserChoice) == 0){
//Do Stuff
}
You want:
if (Users == UserChoice) {
The std::string class (well, really std::basic_string) overloads the == operator (and many others) to do what you want. You should not be using C functions like strcmp in C++ code, and in any case they cannot be directly applied to C++ std::strings.
Comparing strings is the same as comparing int values, char values, etc... . You should use the following method:
string a
string b
if (a == b)
{
// Do something
}
In your case, 'a' and 'b' would be replaced by 'Users', 'UserChoices'. But the basic format of comparing 2 variables of the same type stays the same regardless of the type (I'm not sure whether there are any exceptions to this rule or not).
It is also recommended, just as #latedeveloper mentioned, not to use c-language functions in a c++ program. The 2 languages are NOT interchangeable!
** Helpful tip: Always strive to keep your code as simple as possible. With some exceptions possible, the more complicated you make your code, the more hard you will make it for others to understand your code. To connect it to your case, why use a function strcmp() when you can keep it simple by using the == sign? This is just my 2 bits based on personal experience.
c style:
string a
string b
if(strcmp(a.c_str(),b.c.str()) == 0)
Related
I am extracting a string from a .txt file and saving it in a variable:
std::string line = "The king's name is getKingName()";
Lets assume that getKingName() is a function that returns a King class' name data member.
How can I make a call to getKingName() when the string variable looks like that?
As far as I know, C++ does not provide such kind of functionality to interpolate functions call inside a string. All you can do implement your own logic to do that.
Like,
1) define all the valid methods like this,
string getKingName(){
return "Some name";
}
string otherMethods(){
return "other values";
}
2) One helper method for mapping of function call
string whomToCall(string methodName){
switch(methodName){
case "getKingName()":
return getKingName();
break;
case "otherMethods()":
return otherMethods();
break;
default:
return "No such method exist";
}
}
3) break the line in tokens(words), read one by one and check for following condition also if
token starts with any alphabetical character and ends with "()" substring
istringstream ss(line);
do {
string token;
ss >> token;
if(isMethod(token))
cout << whomToCall(token) << " ";
else
cout << token<< " ";
} while (ss);
4) isMethod() to check if token's value can be a valid method name
bool isMethod(string token){
int n= token.length();
return isalpha(token[0]) && token[n-2]=='(' && token[n-1] == ')' ;
}
This would be the easiest solution, but I think your problem consists of several such calls?
std::string line = "The king's name is getKingName()";
if (line.find("getKingName()") != std::string::npos) {
King name = getKingName();
}
Amended
This answer is a little off subject. I will leave it up, because others might find it relevant, but I agree with other answers, a simple map->function will work better for your case.
This is not supported by C++. C++ is not an interpreted language. If you you want to do things like this, why not use an interpreted language, which do these sorts of things by default. Languages like lua are designed to call C/C++ functions with an interpreted language, with a small overhead.
However, if you really need to do this, it is possible, depending on your operating system. For example,
On windows start with dbghelp. You will need to build a pdb, (e.g. build with symbols).
On linux, you will also need to build symbols (-g), and use something like dlsym see here for a discussion.
That said, there are lots of gotchas doing it this way. Optimization can get in the way (best to disable them). Also best to avoid dynamic linking (prefer static). You will also need to cope with C++ name mangling (the name of the function is not the name of your function in C++). see https://blog.oakbits.com/how-to-mangle-and-demangle-a-c-method-name.html.
I'm using a library called DS3231 by rinkydinkelectronics
Link: http://www.rinkydinkelectronics.com/library.php?id=73 (click on manual)
i'm trying to run the following code
String alarmTime = "08:52:00";
void loop(){
if (rtc.getTimeStr() == alarmTime){
alarmState = true;
}
}
but i get the following error:
exit status 1 no match for 'operator==' (operand types are 'char*' and
'String')
the library manual however says that the return value is a string so I don't see why this shouldn't work :(
Can someone help me fix this or tell me what might be wrong?
Thank you!
If understood your code right, you want to check whether both strings are equal. Because the standard library is not available in the Arduino IDE, you must choose a different way. Convert the C string (char*) to a String object.
Example:
if(String(rtc.getTimerStr()) == alarmTime) {
....
}
This should work.
You're trying to compare two different things with confusingly similar names. A string(C style string) is a null terminated char array. This is different from the String object. It's generally accepted that with extremely memory limited hardware such as the standard Arduino boards you should avoid the use of the String class if possible as it uses more memory and may cause memory fragmentation from dynamic memory allocation. Much better to use strings instead, which are actually pretty much just as easy to work with as String.
Your code using only strings:
char alarmTime[] = "08:52:00";
void loop() {
if (strcmp(rtc.getTimeStr(), alarmTime) == 0) {
alarmState = true;
}
}
This question already has answers here:
C/C++: switch for non-integers
(17 answers)
Closed 9 years ago.
How can I compare an array of char in c++ using switch-case?
Here is a part of my code:
char[256] buff;
switch(buff){
case "Name": printf("%s",buff);
break;
case "Number": printf("Number "%s",buff);
break;
defaul : break
}
I receive the error :" error: switch quantity not an integer".How can I resolve it?
If you really need a switch statement, you will need to convert your buff variable to an integer. To do so, you could use a hash function or a std::map.
The easy approach would be to make a std::map<std::string,int> containing the keys you want to use in the switch associated with unique int values. You would get something like:
std::map<string,int> switchmap;
...
switch(switchmap.find(std::string(buff))->second){
...
}
The std::map approach is very readable and shouldn't cause much confusion.
You just can't use an array as the expression in a switch construct.
In C++ case statements require a constant integer value and cannot be used with values calculated at runtime. However if you are using C++11 you can use a constexpr function to generate case values simulate using strings with a case statement.
This uses a hash function that takes a pointer to a string and generates a value at compile time instead of runtime. If more than one string generates the same value (a hash collision) you get the familiar error message about multiple case statements using the same value.
constexpr unsigned int djb2Hash(const char* str, int index = 0)
{
return !str[index] ? 0x1505 : (djb2Hash(str, index + 1) * 0x21) ^ str[index];
}
The djb2Hash function can then be used directly in both the switch and case statements. There is one caveat however, the hash function can result in a collision at runtime. The probability of this happening is driven primarily by the quality of the hash function. The solution presented here does not attempt to address this problem (but may in the future).
void DoSomething(const char *str)
{
switch(djb2Hash(str))
{
case djb2Hash("Hello"): SayHello(); break;
case djb2Hash("World"): SayWorld(); break;
}
}
This works very well but might be considered ugly. You can simplify this further by declaring a user defined literal that handles invoking the hash function.
// Create a literal type for short-hand case strings
constexpr unsigned int operator"" _C ( const char str[], size_t size)
{
return djb2Hash(str);
}
void DoSomething(const char *str)
{
switch(djb2Hash(str))
{
case "Hello"_C: SayHello(); break;
case "World"_C: SayWorld(); break;
}
}
This provides a more intuitive usage of strings in a switch statements but may also be considered slightly confusing because of the user defined literal.
[Edit: Added note about runtime hash collisions. Much Kudos to R. Martinho Fernandes for bringing it to my attention!]
You cannot use a non-integral type in a switch statement. Your problem would require something like:
char buff[256];
if(!strcmp(buf, "Name") printf("%s",buff);
if(!strcmp(buf, "Number") printf("%s",buff);
To get the results you are looking for - basically a bunch of if statements to replace the switch.
You are trying to do something we all dearly wish we could, but not in C/C++ :) The case in a switch statement must be integral values. One easy alternative is to have an enumeration that matches the set of strings you want to act on.
In C++ you can use a switch-case only with integers (char, int, ...) but not with c-strings (char *)
In your case you have to use a if-then-else construct
if (strcmp(buff, "Name") == 0) {
...
} else if (...) {
...
}
As the error says, switch only works for integers. The simplest resolution is to use a chain of if...else if... tests.
However, using a char array rather than a string is awkward, since you need quirky C-style functions to compare them. I suggest you use std::string instead.
std::string buff;
if (buff == "Name") {
// deal with name
} else if (buff == "Number") {
// deal with number
} else {
// none of the above
}
More complex approaches, perhaps mapping strings to numbers for use in a switch or to functors to call, are possible and may be more efficient if you have a huge number of cases; but you should get the simple version working before worrying about such optimisations.
Unlike many other languages that allow string and other object comparisons to be used in a switch-case, c++ requires that the underlying value be an integer. If you want use more complex object types, you will have to use an if else-if construct.
You can't use a switch directly for this situation.
Typically, you'd want to use a std::map (or std::unordered_map) to store the action to associate with each input. You might (for example) use a std::map<std::string, std::function>, and then store the addresses of functions/function objects in the map, so your final construct would be something like:
std::map<std::string, std::function> funcs;
funcs["Name"] = [](std::string const &n) {std::cout << n;};
funcs["Number"] = [](std::string const &n) {std::cout << "Number: " << n;};
// ...
auto f = funcs[buff];
f(buff);
// or combine lookup and call: funcs[buff](buff);
Two notes: first, you probably really want to use map::find for the second part, so you can detect when/if the string you're looking for isn't present in the map.
Second, as it stands, your code doesn't seem to make much sense -- you're both switching on buff and printing out buff's value, so (for example) if you buff contains Number, your output will be "Number Number". I'd guess you intend to use buff and some other variable that holds the value you care about.
You can partially do a "string" compare.
The below does not specifically satisfy your query (as C won't ride that pony), nor is it elegant code, but a variation on it may get you through your need. I do not recommend you do this if you a learning C/C++, but this construct has worked well in limited programming environment.
(I use it in PIC programming where strlen(buff)==1 or 2 and sizeof(int)==2.)
Let's assume sizeof(int) == 4 and strlen(buff) >= 3.
char buff[256];
// buff assignment code is TBD.
// Form a switch 4-byte key from the string "buff".
// assuming a big endian CPU.
int key = (buff[0] << 3*8) | (buff[1] << 2*8) | (buff[2] << 1*8) | (buff[3] << 0*8);
// if on a little endian machine use:
// int key = (buff[0] << 0*8) | (buff[1] << 1*8) | (buff[2] << 2*8) | (buff[3] << 3*8);
switch (key) {
// Notice the single quote vs. double quote use of constructing case constants.
case 'Name': printf("%s",buff); break;
case 'Numb': printf("Number \"%s\"",buff); break;
default : ;
}
I'm new to c++ coming from a python background.
If I want input from a user and then I want to check what data type the input is (e.g. integer or float), how is it possible for me to declare the variable that I want to assign the user's input to?
Short answer: You can't.
Long answer: You can't. C++ is a statically typed language, meaning that you have to define the type at compile time. Python is dynamically typed, so the type of an object can change from line to line.
If you want to get some input from the user though, you can just use a string though.
For example, if you want to get integer input from the user:
int n;
std::cin >> n;
Float input:
float x;
std::cin >> x;
And so forth. Do note in those two cases, if the user inputs something other than an integer or float, you'll have to check the flags of std::cin to see if there was an error.
But you need to tell the user "Input integer now" or "Input float now". You can't just accept some arbitrary type. Instead, design your code so you have alternative code paths for either integer or floating point input. Or force one or the other, and print an error when they give the wrong type of input.
Don't write your code like you're in Python. Idiomatic Python code is not idiomatic C++ code, and the way you accomplish things will not look the same.
In C++ the way to get arbitrary input would look like:
std::string input;
std::cin >> input;
if (IsInteger(input))
{
// do stuff with integer
}
else if (IsFloat(input))
{
// do stuff with float
}
else
{
std::cout << "Bad Input!" << std::endl;
}
Edit: As MSalters pointed out in a comment, You can actually use boost::lexical_cast<T>(expr) to cast a string representation to some type T (Where T is usually something like int, float, double, etc). Do note, you'll probably still have to do some checking to see if expr is actually an integer, float, or otherwise.
When you get input from the user, it will arrive as a string. For example:
std::string inp;
std::cin >> inp;
Then, you take the contents of inp (which is whatever the user typed), and look inside it to see what characters it contains. At that point you could make decisions based on whether it contains (a) all digits, (b) digits and a decimal point, or (c) something else entirely.
Much better to collect a string from the user and then parse it.
This question is the place to look for an answer:
How to parse an int from a string
C++ is a statically typed language. All the variable types must be known at compilation time.
Python is dynamically typed language and on the contrary, c/c++ are statically typed languages. It is not possible to find the the type and declare at run time.
Greetings!
Lets cut the excessive intro this time and get straight to the point.
I have a problem in C++ using the isalnum method.
the code:
int playAgainst = 0;
do
{
cout << "Who do you want to play against?(1/2)\n";
cout << "1: Human player\n";
cout << "2: Computer player\n";
cin >> playAgainst
} while(!isalnum(playAgainst) && playAgainst != 0);
As seen in the code, I'm providing the user with a choice. Play against human or play against a computer.
What I want is, as long as the user enters anything else then an integer value(cin >> playAgainst) to repeat the question. However, If i enter a char, or string value, it keeps looping endlessly. I am not 100% sure, but it would be obvious, if the problem is, that the non int value is already saved as the value for playAgainst.. How can I check in this bit of code if the input value is int before saving it?
Or is the only possibility to save as a char/string and then check?
If the latter is the case, a new problem arises. isalnum only accepts int as parameter, atleast from what I know. How will I check if that string or char is an int?
Thank you for taking the time to read. And hopefully Ill be accepting a reply as answer soon ^^
Thanks everyone for the answers.
I have gotten what I wanted, and everything has been solved.
The reason I chose for the accepted answer, is well... because initially, it made my code work the way I want it to. I want to accept multiple answers though..
Make playAgainst a char and compare against '0', not 0. Right now, the user has to enter the ASCII (or whatever your character set is) code for the character '1' or '2'.
isalnum won't work on ints outside the valid range of char, except for EOF. (The fact that it takes an int argument is a leftover from C, which has different integer promotions rules than C++. to accomodate for EOF.)
Remove the isalnum() check. cin >> playAgainst will convert anything except a number to zero, which will be caught by the second check. Note that this is only an option because zero is not a valid input.
isalnum() is useful if you're interpreting the characters yourself, but in this case the stream has already done that for you.
This is how the compiler will implement isalnum:
int isalnum (int ch)
{
return (ch >= 'a' && ch <= 'z') ||
(ch >= 'A' && ch <= 'Z') ||
(ch >= '0' && ch <= '9');
}
So you might as well write that code snippet in your own code, and it will be equivalent with an inlined version of isalnum.
It's because you don't clear the buffer. When the input is invalid, you need to clear it from the buffer, and then you can move on to the next input, else you're trying to extract the same input every time (which fails, because it's the same bad input), and thus enter an infinite loop.
The problem is that you're inputing an int, and not a char. And if the
text in the input isn't an int, then the input fails. In which case,
playAgainst isn't modified, and the failure is memorized in std::cin
until you explicitly clear the error. And inputting from a stream in an
error state is a no-op. What you probably want to do is
Input a single character: if you don't want to skip spaces, using
`std::cin.get( ch )` or `ch = std::cin.get()`. (In the latter
case, `ch` should be an `int`, since it must also handle `EOF`.
On the other hand, you can use `::isalnum` on it directly, which
you can't do if `ch` is a `char`.
Fully check for valid input: not just `::isalnum`, but rather
whether the input is a legal selector in your list. Something
along the lines of:
ch != EOF && std::find( legalChars.begin(), legalChars.end(), (char)ch ) != legalChars.end()
In case of error, clear any remaining input, say with:
std::cin.ignore(INT_MAX, '\n');
In practice, you'll probably want to treat EOF differently from
an erroneous command. (If you don't clear the input after EOF, you
won't be able to read anything else. But presumably, if you got EOF,
it's because the user gave up, and doesn't want to try any more.)
Finally, it's probably preferrable to keep all of the information in
a common location, using a table of:
struct Command
{
char op;
char const* prompt;
void (* func)();
};
You then loop over a table of these to output the prompt, search it to
see if the character was legal, and finally, call the function on the
entry you found. Or define an abstract base class, a concrete class
deriving from it for each command, and use an std::map<char,
AbstractBase*> for the mapping, etc. Very C++, but perhaps a bit
overkill for such a simple case.
Why not use isdigit().