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.
Related
I'm trying to get my head around how to split arrays and use the tokens in an if statement, however I'm not having much luck.
The below code is for an Arduino. What I am doing is passing the function receviedChars which will be something like:
token0,token1,token2
When i print out func, it reads out c, so I figured that if I compared func to c it should match true. Unfortunately, this doesn't seem to happen.
I'm quite new to C++ and Arduino, and mainly have a web development background so I might be misinterpreting something
const byte numChars = 32;
char receivedChars[numChars];
char *chars_array = strtok(receivedChars, ",");
char *func = chars_array;
Serial.println(func);
if(func == 'c') {
Serial.println("It works");
}
Could someone help me with where I am going wrong please?
First of all, strtok works iteratively. This means that to split a string into tokens you have to call it until it returns NULL:
char* token = strtok(input, ",");
while (token)
{
...
token = strtok(NULL, ",");
}
And the second thing to know is that char * is just a pointer to a block of memory treated as a string. So when you write something like:
char* str = ...;
if (str == 'c')
{
...
}
This actually means "compare an address pointed by variable 'str' with a value of an ASCII code of character 'c' (which is 0x63 in hex)", therefore your condition will be true iff the pointer returned by strtok equals to 0x63 and that is definitely not what you want.
What you really need is strcmp function, that compares two blocks of memory character by character:
char* chars_array = strtok(receivedChars, ",");
if (strcmp(chars_array, "bla") == 0)
{
// a first token is "bla"
}
Swap
if(func == 'c') {
to
if(func[0] == 'c') {
if you want to check if first char is 'c'
'func' is a pointer to the start of an array of characters; comparing it to a character value will almost never yield true. Perhaps you want to compare the character in that array instead.
The main issue is that you should use if(*func == 'c') {, i.e. dereference pointer func, instead of if(func == 'c') {.
Note that you additionally should consider that chars_array might be an empty string or might comprise only ','-characters; in this case, strtok will yield NULL, and probably lets your app crash. Hence, the code should look as follows:
if (func != nullptr) {
Serial.println(func);
if(*func == 'c') {
Serial.println("It works");
}
}
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.
How to detect if atof or _wtof failes to convert the string to double? But not by trying to check if the result is different form 0.0 because my input can be 0.0. Thanks!
Don't use atof. Instead, use strtod, from <cstdlib>, and also check errno from <cerrno>:
// assume: "char * mystr" is a null-terminated string
char * e;
errno = 0;
double x = std::strtod(mystring, &e);
if (*e != '\0' || // error, we didn't consume the entire string
errno != 0 ) // error, overflow or underflow
{
// fail
}
The pointer e points one past the last consumed character. You can also check e == mystr to see if any characters got consumed.
There's also std::wcstod for working with wchar_t-strings, from <cwstring>.
In C++11 you also have std::to_string/std::to_wstring, from <string>, but I believe that throws an exception if the conversion fails, which may not be a desirable failure mode when dealing with external data.
Using atof, you can't. But since this is C++, I suggest you use a std::stringstream and check it with operator ! after applying operator >> to a double.
I'm using a file system library and I'm trying to create a readline function.
int al_fgetc(ALLEGRO_FILE *f)
Introduced in 5.0.0
Read and return next byte in the given file. Returns EOF on end of file or if an error occurred.
That is the function I'm using from the library. What I want to do is += the resulting char into a std string if it is != EOF which is -1. I'm just not sure if I need to cast it to get the correct result. Will something like this do it:
bool File::readLine( std::string& buff )
{
if(eof() || !isOpen())
{
return false;
}
buff = "";
int c = 0;
while(c = al_fgetc(m_file) != EOF && c != '\n')
{
buff += (char)c;
}
return buff.length() > 0;
}
I'm going to be reading utf-8 from file so I need to make sure this works correctly.
Thanks
Yes, this will work, except you need an extra set of parentheses because the != operator has higher precedence than the = operator:
while((c = al_fgetc(m_file)) != EOF && c != '\n')
...
The only reason that fgetc returns int instead of char is that there are 257 possible return values: all 256 possible bytes, or EOF, which signals that there's no more data left in the file. It will always return either 0-255 or EOF, so it's safe to cast the return value to char or unsigned char once you've tested it for EOF.
Yeah, the only reason why they return int is because there is no "free" value in a char that could be used for the EOF signaling. Thus, checking that it's not EOF and afterwards casting it back to char is precisely what they expect you to do.
Try using feof(m_file) to check that you've hit the end of file rather than checking the character returned by fgetc. This should seperate your read loop from the eof check, so no casting is necessary.
I have a const char* variable which takes values from a function that I have wrote.
When I write this variable to a file many times it writes nothing. So it must be empty or filled in with space.The strange thing is that in the txt file that I write it changes line every time, when it has value or not.Why is that?Does it mean that the returned value from the function has a \n?
how can I check if a value of a const char * is empty or in general how can I check character by character the value in char*?
Since C/C++ pointers can be interpreted as arrays of values the pointers point to, the two ways of checking values of a char* is by applying an indexing operator or by using pointer arithmetics. You can do this:
const char *p = myFunctionReturningConstChar();
for (int i = 0 ; p[i] ; i++) {
if (p[i] == '\n') printf("New line\n");
}
or this:
const char *p = myFunctionReturningConstChar();
while (*p) {
if (*p == '\n') printf("New line\n");
p++;
}
In addition, C++ library provides multiple functions for working with C strings. You may find strlen helpful to check if your pointer points to an empty string.