How do I examine the first character of a QString? - c++

I want the following code to remove a leading zero from a price (0.00 should be cut to .00)
QString price1 = "0.00";
if( price1.at( 0 ) == "0" ) price1.remove( 0 );
This gives me the following error: "error: conversion from ‘const char [2]’ to ‘QChar’ is ambiguous"

The main issue is that Qt is seeing "0" as a null-terminated ASCII string, hence the compiler message about const char[2].
Also, QString::remove() takes two arguments. So you code should be:
if( price1.at( 0 ) == '0' ) price1.remove( 0, 1 );
This builds and runs on my system (Qt 4.7.3, VS2005).

Try this:
price1.at( 0 ) == '0' ?

The problem is that the 'at' function returns a QChar which is an object that can't be compared to the native char/string "0". You have a few choices, but I'll just put two here:
if( price1.at(0).toAscii() == '0')
or
if( price1.at(0).digitValue() == 0)
digitValue returns -1 if the char is not a digit.

QString s("foobar");
if (s[0]=="f") {
return;
}

QChar QString::front() const Returns the first character in the
string. Same as at(0).
This function is provided for STL compatibility.
Warning: Calling this function on an empty string constitutes
undefined behavior.
http://doc.qt.io/qt-5/qstring.html#front
QString s("foobar");
/* If string is not empty or null, check to see if the first character equals f */
if (!s.isEmpty() && s.front()=="f") {
return;
}

Related

Using strtok tokens in if statements

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");
}
}

strtol giving same answer for two different hex strings

So I have two hex strings - "3b101c091d53320c000910" and "071d154502010a04000419". When I use strtol() on them I get same value for both strings.
I tried the following code-
string t1="3b101c091d53320c000910";
long int hext1=strtol(t1.c_str(),0,16);
string t2="071d154502010a04000419";
long int hext2=strtol(t2.c_str(),0,16);
cout<<hext1<<endl;
cout<<hext2<<endl;
Both are giving me same value: 9223372036854775807.
I dont know how strtol() works exactly since I am new to C++ but it's giving me same value for two different hex strings. Why?
You should start by reading the manual page. It's returning LONG_MAX since you're input is too large to fit in a long.
Also, strtol() is a very C way of doing things, and you're programming in C++.
You're not using strtol correctly. You should set errno to
0 before calling it, and check that it is still 0 after;
otherwise, it will contain an error code (which can be displayed
using strerror). Also, you should pass it the address of
a char const*, so that you can ensure that it has processed
the entire string (otherwise, "abc" will return 0, without an
error):
errno = 0;
char const* end;
long hext1 = strtol( t1.c_str(), &end, 16 );
if ( errno != 0 || *end != '\0' ) {
// Error occured.
}

How to Peek Ahead at a Character Without Passing that Character?

I am doing an implementation of an expression evaluator where the user can type in a binary number with the 0b prefix. I want to be able to (using a string iterator), peek ahead to see if the next character in the expression after the 0 is a b, and if it is, to not pass by that b character and to go back a character to the 0 at the start of the prefix (something like ungetc). Is there a way to unget a character that has been passed over in a string?
What I've tried:
Token::pointer_type Tokenizer::_get_number( Tokenizer::string_type::const_iterator& currentChar, Tokenizer::string_type const& expression )
{
assert( isdigit( *currentChar ) && "currentChar must pointer to a digit" );
Integer::value_type const MAX_UNSIGNED_D10 = (std::numeric_limits<Integer::value_type>::max()-10)/10;
Integer::value_type accumulator = *currentChar++ - '0';
//Binary Numbers
if( *currentChar == '0' )
{
if( *currentChar++ == 'b' )
{
BinaryInteger::value_type binAccum = _get_binary( currentChar, expression );
return make<BinaryInteger>( binAccum );
}
}
}
Token::pointer_type Tokenizer::_get_number( Tokenizer::string_type::const_iterator& currentChar, Tokenizer::string_type const& expression )
{
assert( isdigit( *currentChar ) && "currentChar must pointer to a digit" );
Integer::value_type const MAX_UNSIGNED_D10 = (std::numeric_limits<Integer::value_type>::max()-10)/10;
Integer::value_type accumulator = *currentChar++ - '0';
std::stringstream iss( expression );
//Binary Numbers
if( iss.get() == '0' )
{
if( iss.get() == 'b' )
{
BinaryInteger::value_type binAccum = _get_binary( currentChar, expression );
return make<BinaryInteger>( binAccum );
}
}
}
Also have tried using [] access for the string expression's characters itself but that is extremely limiting to certain cases.
When you call the ++ operator on an iterator, it advances the iterator to the next element. To peek at the next element without advancing the iterator, you can use +1 instead, eg:
if( *currentChar == '0' )
{
if( *(currentChar+1) == 'b' )
{
BinaryInteger::value_type binAccum = _get_binary( currentChar+2, expression );
return make<BinaryInteger>( binAccum );
}
}
Just be careful if currentChar is already at the end of the string before you peek. The next element after the current one will be the string's end position, and you should not dereference that iterator value. You might want to consider adding an extra parameter to your tokenizer so it can detect when it reaches the end of the input string and does not iterate too far.
I believe stringstream peek is what you need (it's inherited from istream, just like unget. Stringstraems are streams working with string. They work the same as file streams and the default I/O streams like cin and cout.

How to convert string to unsigned long in C++? [duplicate]

This question already has answers here:
C++ convert hex string to signed integer
(10 answers)
Closed 9 years ago.
I need help in programming. The program has to accept a string that will eventually be turned to unsigned long. But here's the catch, there must be an error catcher that when you enter combination of hex and symbols like a!!!!!! will produce an error and the unsigned long variable must be able to accept and store the input greater that 4294967295 which is FFFFFFFF. I've tried this code segment:
char buffer[256];
unsigned long holder;
fgets(buffer,256,stdin);
holder = strtoul (buffer,NULL,16);
My problem is that when I enter FFFFFFFFF (9 F's) instead of FFFFFFFF (8 F's), the holder will STILL accept 4294967295 even though its more than the. Another thing is that when I combine both hex and symbols like a!!!!!, the fgets still consider the hex A.
Can you please give me an idea on how to do this? If you know any other idea besides this code, please do let me know. Thanks!
So if you look at this document for strtoul you will see this under the Return Value section:
If the converted value falls out of range of corresponding return type, range error occurs and ULONG_MAX or ULLONG_MAX is returned.
So for out of range check you need code similar to this:
if ( ( holder == ULONG_MAX || holder == ULLONG_MAX ) && errno == ERANGE)
For the a!!!! case looking back at the same document, you will see:
The functions sets the pointer pointed to by str_end to point to the character past the last character interpreted. If str_end is NULL, it is ignored.
you are currently passing in NULL but if you pass in an argument:
char *p;
holder = strtoul (buffer,&p,16);
you can now check whether if *p is a NULL terminator and if so then you processed all the characters otherwise you know you had an issue.
You also have the option of using stoul which throw the following exceptions std::invalid_argument if no conversion could be performed and std::out_of_range if the converted value would fall out of the range of the result type.
For example you could do as follows:
std::string str1(n) ;
size_t pos ;
try
{
holder = std::stoul( str1, &pos, 16 ) ;
}
catch( std::invalid_argument e )
{
std::cout << "Invalid argument" << std::endl ;
}
catch ( std::out_of_range e )
{
std::cout << "Out of range" << std::endl ;
}
pos will be the index of the last character processed, in your case if pos != str1.length() then it could not process the whole string and your have a problem.
If you are using the "old C-style strings", then you can add extra checks to see that "all characters were taken" by passing a char * to the strtoul call.
In other words:
char *end_ptr = NULL;
....
errno = 0;
holder = strtoul(buffer, &end_ptr, 16);
The end_ptr will point at the character one past the accepted input, so if you enter "a!!!!!", it will point at a '!'.
if (end_ptr != '\0') // Should point at "end of string marker".
{
... do something to indicate error.
}
To detect overflow, you will have to rely on errno:
if (errno != 0)
{
... deal with errors here .
}
Obviously, you can do:
if (errno != 0 || *end_ptr != '\0')
{
.... deal with errors.
}
Using the C++ std:stoul() function will throw an exception, so the C++ style solution would be something like:
try
{
holder = std::stoul(buffer);
}
catch(...)
{
... deal with error ...
}
As other posters have said - use stoul if you have it.
If you don't, you might be able to do something like:
std::istringstream strm( buffer );
unsigned long holder = 1;
strm >> std::hex >> holder;
if( strm.fail() )
// out-of-range
if( ! strm.eof() )
// didn't read all available characters - catches "A!!!"

Managed c++/cli .net convert fixed Byte array to a String^

How do I convert a fixed byte array to a String in managed c++/cli ?
For example I have the following Byte array.
Byte byte_data[5];
byte_data[0]='a';
byte_data[1]='b';
byte_data[2]='c';
byte_data[3]='d';
byte_data[4]='e';
I have tried the following code
String ^mytext=System::Text::UTF8Encoding::UTF8->GetString(byte_data);
I get the following error:
error C2664: 'System::String ^System::Text::Encoding::GetString(cli::array<Type,dimension> ^)' : cannot convert parameter 1 from 'unsigned char [5]' to 'cli::array<Type,dimension> ^'
Arm yourself with some knowledge about casting between pointers to signed and unsigned types and then you should be set to use String::String(SByte*, Int32, Int32). It might also pay to read the Remarks on the page, specifically around encoding.
I've reproduced the sample from the page here:
// Null terminated ASCII characters in a simple char array
char charArray3[4] = {0x41,0x42,0x43,0x00};
char * pstr3 = &charArray3[ 0 ];
String^ szAsciiUpper = gcnew String( pstr3 );
char charArray4[4] = {0x61,0x62,0x63,0x00};
char * pstr4 = &charArray4[ 0 ];
String^ szAsciiLower = gcnew String( pstr4,0,sizeof(charArray4) );
// Prints "ABC abc"
Console::WriteLine( String::Concat( szAsciiUpper, " ", szAsciiLower ) );
// Compare Strings - the result is true
Console::WriteLine( String::Concat( "The Strings are equal when capitalized ? ", (0 == String::Compare( szAsciiUpper->ToUpper(), szAsciiLower->ToUpper() ) ? (String^)"TRUE" : "FALSE") ) );
// This is the effective equivalent of another Compare method, which ignores case
Console::WriteLine( String::Concat( "The Strings are equal when capitalized ? ", (0 == String::Compare( szAsciiUpper, szAsciiLower, true ) ? (String^)"TRUE" : "FALSE") ) );
Here is one option:
array<Byte>^ array_data = gcnew array<Byte>(5);
for(int i = 0; i < 5; i++)
array_data[i] = byte_data[i];
System::Text::UTF8Encoding::UTF8->GetString(array_data);
Not compiled but I think you get the idea.
Or use the String constructor, as indicated by #ta.speot.is, with encoding set to System.Text::UTF8Encoding.
For those interested in another working solution. I used the notes of ta.speot.is and developed a working solution,You should be able to use this solution or that provided by Rasmus.
Byte byte_data[5];
byte_data[0]='a';
byte_data[1]='b';
byte_data[2]='c';
byte_data[3]='d';
byte_data[4]='e';
char *pstr3 = reinterpret_cast<char*>(byte_data);
String^ example1 = gcnew String( pstr3 );//Note: This method FAILS if the string is not null terminated
//After executing this line the string contains garbage on the end example1="abcde<IqMŸÖð"
String^ example2 = gcnew String( pstr3,0,sizeof(byte_data)); //String Example 2 correctly contains the expected string even if it isn't null terminated