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!!!"
Related
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.
}
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.
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.