Comparing const char to a string - c++

I have an issue comparing a const char to a string... If I use Com_Printf ("%s", value);
It returns what I want (0.3c), but how can I convert value to a string and compare that to 0.3c? This is what I have:
value = SearchInfostring(msg, "shortversion");
if (value != "0.3c")
{
Com_Printf (MSG_WARNING,
Com_Printf (MSG_WARNING,
"> WARNING: Value: Should be 0.3c, is: %s \n",
value);
//Run stuff
}
That returns:
WARNING: Value: Should be 0.3c, is: 0.3c

If value is of type const char*, expression
value != "0.3c"
is comparing two pointers (addresses), not strings. You want to compare string and a string literal so can use strcmp:
if(strcmp(value, "0.3c"))
{
// strings are not equal
}
else
{
// strings are equal
}
Bear in mind that preferred string type in C++ is std::string.

Use an std::string for value.
std::string value = SearchInfoString(msg, "shortversion");
Then, you can compare it normally. If you cannot use a string at all for whatever reason (the return value can be converted), use strcmp.
if (strcmp (value, "0.3c") != 0)
{
...
}

It seems that SearchInfoString returns a char *, based on the way you use it with Com_Printf. Therefore you can just use strcmp() to compare value to "0.3c". For example:
if (strcmp(value, "0.3c") != 0)
{
// Print warning
}

Related

What is a char* when set equal to ""?

I am trying to write my own string class for an assignment, and I was wondering how I should treat the argument of "".
For example, if there is a call of:
s = myString("")
what is the length, and what are the contents of the char* holding the data in my 'myString' class?
The char * passed to you will be a pointer to an "null" terminated list of char's which, most likely, will be a single, immutable char whose value is 0 (or "null").
For example...
const char* s = "";
char value = *s;
int length = strlen(s);
... should result in...
s == [compiler defined]
!value == true
length == 0

Can someone explain this code line by line?

This method
bool isNumber(string input)
{
char* p;
strtod(input.c_str(), &p);
return *p == 0;
}
should input a string and convert it to a double. But I do not understand the process of it. Can someone explain this to me in detail, line by line? And also, shouldn't bool be changed to double since it's not returning a true or false value? Thanks.
strtod tries to convert the string to a double. It also sets the p parameter to point to the position where the conversion ended.
If the conversion used all the characters in the string - if they were all part of a number - the pointer p will point to the '\0' terminator of the string.
So, return *p == 0, or better return *p == '\0', tells us if we reached the end of the string. And, of course, == returns a bool result.

How to convert string (char*) to number with error checking using standard library functions?

I can think of 2 ways to convert a string to int: strtol and std::stringstream. The former doesn't report errors (if string is not a representation of a number), the latter throws an exception BUT it is too relaxed. An example:
std::wstring wstr("-123a45");
int result = 0;
try { ss >> result; }
catch (std::exception&)
{
// error handling
}
I want to detect an error here because the whole string is not convertible to int, but no exception is being thrown and result is set to -123.
How can I solve my task using standard C++ facilities?
You erroneously believe that strtol() does not provide error checking, but that is not true. The second parameter to strtol() can be used to detect if the entire string was consumed.
char *endptr;
int result = strtol("-123a45", &endptr, 10);
if (*endptr != '\0') {
/*...input is not a decimal number */
}
There's std::stoi, or std::strtol.
The first throws an exception (and is in C++11 and later), the other you have to manually check (as it's originally a standard C function).
And you can indeed use std::strtol to check that a string is a valid number:
char some_string[] = "...";
char *endptr;
long value = std::strtol(some_string, &endptr, 10);
if (endptr == some_string)
{
// Not a valid number at all
}
else if (*endptr != '\0')
{
// String begins with a valid number, but also contains something else after the number
}
else
{
// String is a number
}
An alternative approach, you could convert to an int, and then convert that back into a wstring, and check the strings for equality.
Not a good idea for doubles, and you would probably need to trim the input string of whitespace even for ints.

Basics of strtol?

I am really confused. I have to be missing something rather simple but nothing I am reading about strtol() is making sense. Can someone spell it out for me in a really basic way, as well as give an example for how I might get something like the following to work?
string input = getUserInput;
int numberinput = strtol(input,?,?);
The first argument is the string. It has to be passed in as a C string, so if you have a std::string use .c_str() first.
The second argument is optional, and specifies a char * to store a pointer to the character after the end of the number. This is useful when converting a string containing several integers, but if you don't need it, just set this argument to NULL.
The third argument is the radix (base) to convert. strtol can do anything from binary (base 2) to base 36. If you want strtol to pick the base automatically based on prefix, pass in 0.
So, the simplest usage would be
long l = strtol(input.c_str(), NULL, 0);
If you know you are getting decimal numbers:
long l = strtol(input.c_str(), NULL, 10);
strtol returns 0 if there are no convertible characters at the start of the string. If you want to check if strtol succeeded, use the middle argument:
const char *s = input.c_str();
char *t;
long l = strtol(s, &t, 10);
if(s == t) {
/* strtol failed */
}
If you're using C++11, use stol instead:
long l = stol(input);
Alternately, you can just use a stringstream, which has the advantage of being able to read many items with ease just like cin:
stringstream ss(input);
long l;
ss >> l;
Suppose you're given a string char const * str. Now convert it like this:
#include <cstdlib>
#include <cerrno>
char * e;
errno = 0;
long n = std::strtol(str, &e, 0);
The last argument 0 determines the number base you want to apply; 0 means "auto-detect". Other sensible values are 8, 10 or 16.
Next you need to inspect the end pointer e. This points to the character after the consumed input. Thus if all input was consumed, it points to the null-terminator.
if (*e != '\0') { /* error, die */ }
It's also possible to allow for partial input consumption using e, but that's the sort of stuff that you'll understand when you actually need it.
Lastly, you should check for errors, which can essentially only be overflow errors if the input doesn't fit into the destination type:
if (errno != 0) { /* error, die */ }
In C++, it might be preferable to use std::stol, though you don't get to pick the number base in this case:
#include <string>
try { long n = std::stol(str); }
catch (std::invalid_argument const & e) { /* error */ }
catch (std::out_of_range const & e) { /* error */ }
Quote from C++ reference:
long int strtol ( const char * str, char ** endptr, int base );
Convert string to long integer
Parses the C string str interpreting its content as an integral number of the specified base, which is returned as a long int value. If endptr is not a null pointer, the function also sets the value of endptr to point to the first character after the number.
So try something like
long l = strtol(pointerToStartOfString, NULL, 0)
I always use simply strol(str,0,0) - it returns long value. 0 for radix (last parameter) means to auto-detect it from input string, so both 0x10 as hex and 10 as decimal could be used in input string.

D2: empty string in a conditional statement

In the following code, why does 2 give output but not 3? The removechars statement returns a string with length 0
import std.stdio, std.string;
void main() {
string str = null;
if (str) writeln(1); // no
str = "";
if (str) writeln(2); // yes
if (",&%$".removechars(r"^a-z")) writeln(3); // no
}
Edit: Ok, it may return null, but I'm still a bit puzzled because all of these print true
writeln(",&%$".removechars(r"^a-z") == "");
writeln(",&%$".removechars(r"^a-z") == null);
writeln(",&%$".removechars(r"^a-z").length == 0);
Edit 2: This also prints true, but put either of them in a conditional and you get a different result
writeln("" == null);
Edit 3: Alright, I understand that I cannot test for an empty string the way I did. What led to this question is the following situation. I want to remove chars from a word, but don't want to store an empty string:
if (auto w = word.removechars(r"^a-z"))
wordcount[w]++;
This works when I try it, but that must be because removechars is returning null rather than ""
Because removeChars will return null when no characters match.
(This happens because .dup of an empty string will always be null.)
D arrays, or slices if you prefer, are interesting beasts.
In D an empty array is equal to null, or more appropriately a null array is equal to an empty array, this is why assert("" == null) or assert([] == null). However when using just if(str) you're asking if there is a string here, and for null there isn't an array. It is equivalent to an empty array, but one does not exist.
The proper way to check if something is null: assert(str is null). I'm not sure which is best for converting a string to a bool, but really there can't be a perfect solution because string isn't a boolean.
Always use is and !is (is not) to compare with null. If you want to check if a string is empty check against its length property:
string str;
assert(str is null); // str is null
assert(!str); // str is null
str = "";
assert(str !is null); // no longer null
assert(str); // no longer null
assert(!str.length); // but it's zero length
if(!str.length) {
//dosomething ...
}