Converting strings to ints or doubles - c++

I know this is a repeated question, and I a have looked at a lot of answers for it but none have really been able to help me so far.
I need to be able to pass various strings into two methods one returns a double and the other a int.
The main problem is that I need strict error checking on both methods so that if I pass a string that dose not contain a number and only a number the method does not make a conversion. As I said I've seen a few solutions but the only good one I've seen (that was able to follow) was using Boost which I do not want to use. As for the answer I was not able to follow here is a part of it copied from
How to parse a string to an int in C++?
The best solution
Fortunately, somebody has already solved all of the above problems. The C standard library contains strtol and family which have none of these problems.
enum STR2INT_ERROR { SUCCESS, OVERFLOW, UNDERFLOW, INCONVERTIBLE };
STR2INT_ERROR str2int (int &i, char const *s, int base = 0)
{
char *end;
long l;
errno = 0;
l = strtol(s, &end, base);
if ((errno == ERANGE && l == LONG_MAX) || l > INT_MAX) {
return OVERFLOW;
}
if ((errno == ERANGE && l == LONG_MIN) || l < INT_MIN) {
return UNDERFLOW;
}
if (*s == '\0' || *end != '\0') {
return INCONVERTIBLE;
}
i = l;
return SUCCESS;
}
If anyone can explain it a little more I think it is the answer Im looking for I just cant get enough of a grasp of what its doing so that i can apply the idea to my code.

Using strtol (and strtod for doubles) sounds like the right approach. The implementation that you quoted flows straight from the documentation for strtol:
It sets errno to zero before the call (strtol does not change errno on success)
It examines errno upon return of strtol to see if an error has been signaled
The final condition checks that the input is not empty, and that the entire input has been consumed by strtol.
An implementation for doubles would look the same, except you'd use strtod.

As a learning exercise, you might want to try to write this on your own. I suggest starting with some examples. You might want to start by getting a firm grasp on how numbers are represented in writing. What does "42" mean? In other words, what does the 2 represent and what does the 4 represent? Similarly, what does "1000000" mean? Once you get a grasp on these concepts, write down the steps (in English) you would take to convert a string into an integer. From there, start converting it into code. If you get stuck anywhere along the way, feel free to come back with more questions.

I re-worded this question in another location and finally got the answer I was looking for. For any wondering here is the link:
Basics of strtol?

Related

Why can't I read apostrophes using ifstream without it crashing?

I'm using this code:
std::string word;
std::ifstream f((file_name + ".txt").c_str());
while (f >> word) {
good_input = true;
for (int i = 0; i < word.length(); ++i) {
if (ispunct(word.at(i))) {
word.erase(i--, 1);
}
else if (isupper(word.at(i))){
word.at(i) = tolower(word.at(i));
}
}
Every time I read the word "doesn't" from a text file, I get this error:
Debug Assertion Failed!
Program: directory\SortingWords(Length).exe
File: minkernel\crts\ucrt\src\appcrt\convert\istype.cpp
Line: 36
Expression: c >= -1 && c <= 255
For more information please visit... [etc.]
When I click "abort", my program exits with code 3. Don't know if that's helpful?
It looks like it's got something to do with the apostrophe maybe? This code works find for all other words in my document up until this one. And works great with documents that don't include apostrophes, yet they include plenty of other punctuation...
I tried changing the encoding of the text file (simply made with notepad), but that didn't help. Generally found lots of complaints about apostrophes but no working answers. Can anyone help me figure out what's going on?
As documentation for ispunct says:
The behavior is undefined if the value of ch is not representable as
unsigned char and is not equal to EOF.
Visual C++ is nice enough to add an almost explicit message for this error if you link to the debug runtime (this is often the case with undefined behaviour - with the release runtime, it just crashes or behaves strangely; with the debug runtime, you get an error dialog box).
In theory, this means that in the character set used by your environment, ' is not representable as an unsigned char, i.e. its character code is too big or too low.
In practice, this seems very unlikely and perhaps even impossible on Windows. It is much more likely that your file doesn't really contain an apostrophe but a character that merely looks like one, e.g. an accent: ´
Here's how you can reproduce the problem in a simple manner:
#include <ctype.h>
int main()
{
ispunct('\'');
ispunct('´'); // undefined behaviour (crash or error message with Visual C++)
}
isupper has the same problem.
You can use those functions safely with static_cast, e.g.:
if (ispunct(static_cast<unsigned char>(word.at(i))))
Of course, now ispunct will return zero for the character. If you really need to cover ´, you have to do so explicitly, for example with a helper function like this:
bool extended_ispunct(int c)
{
return static_cast<unsigned char>(c) || c == '´';
}

How To Compare Strings In C++?

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)

Is it acceptable to initialize temporary strings to keep conditionals readable?

This applies to any language, but for now, let's look at c++. Suppose we have two chars that must take a hexadecimal value:
char b, t;
do {
//some code
} while(((b<'0' || b>'9') && (b<'A' || b>'F')) || ((t<'0' || t>'9') && (t<'A' || t>'F')));
Phew that last conditional looks scary. Let's look at an alternate:
char b, t;
do {
//some code
} while(string(1,b).find_first_of("0123456789ABCDEF")==-1 || string(1,t).find_first_of("0123456789ABCDEF")==-1);
The code still looks very messy, but at least we can understand what is going on: a couple of strings are initialized to see if there is a hex character in them.
Assuming there is no difference in performance, is the second solution better than the first one, or is there another way to see if a char contains a hex value without inflating the code?
The chars' case can be changed in the loop to ALLCAPS or lowercase, if necessary (currently ALLCAPS).
I think you are looking for std::isxdigit.

How does this C++ code work?

enum STR2INT_ERROR { SUCCESS, OVERFLOW, UNDERFLOW, INCONVERTIBLE };
STR2INT_ERROR str2int (int &i, char const *s, int base = 0)
{
char *end;
long l;
errno = 0;
l = strtol(s, &end, base);
if ((errno == ERANGE && l == LONG_MAX) || l > INT_MAX) {
return OVERFLOW;
}
if ((errno == ERANGE && l == LONG_MIN) || l < INT_MIN) {
return UNDERFLOW;
}
if (*s == '\0' || *end != '\0') {
return INCONVERTIBLE;
}
i = l;
return SUCCESS;
}
I'm trying to write a program that can parse strings read in from a file into integer values. While looking for a method to do this I found this piece of code above on a stackoverflow post:
How to parse a string to an int in C++?
However, I can't understand how it works.
Specifically, why is the programmer checking if errno == ERANGE if errno is assigned to 0? (is ERANGE a special value? )
secondly, what does "char const *s" - in the arguments list- mean?
PS: I'm not very experienced when it comes to C++ programming.
The code is using strtol() to do the parsing. This is a standard C library function. You can find documentation on strtol() here amongst other places:
strtol() man page on die.net
The errno variable is a special global variable defined by the standard C library. If a function encounters an error it is set to an error code. So while errno is assigned zero at the start of the routine, the strtol() function will assign a new value to errno if it encounters an error. The following if-statements are checking for the overflow and underflow error conditions.
The char const *s parameter is the string to be parsed. Its a pointer to a constant (read-only) string of characters. By convention strings are terminated by a NULL byte.
Whenever I have done string to int conversions in C++ I used the atoi method. There should be plenty of examples online that suit what you want to do
Most of the specialness here is with errno, not the values being compared to.
errno is a global that's used by some (especially older) library functions to signal errors. You assign 0 to it (which implicitly means there's no problem). Then, if it runs into a problem, a library function can assign some non-zero value to it to tell you want went wrong.
After calling the library function, you then typically check 1) whether it's now non-zero, and 2) if so, what value it has. Based on the value that's been assigned, you can react to the type of error that arose.
I should add, however, that many uses of errno are mostly non-portable. The C standard says that errno exists, that no library function assigns 0 to errno, but not a lot more more than that. It does not specify what non-zero values any particular function may assign to it (well, it specifies some non-zero values that some functions assign, but doesn't limit assignments to those values or those functions).
First of all, this is clearly a C program in C++ disguise.
strtol is a function from standard C library, which does the actual work. Its doumentation may be accessed there: http://linux.die.net/man/3/strtol
All other things are just preliminaries and checks.
errno is a special global variable from the C library which may be modified by standard functions in order to set an appropriate error code (yes, it's C legacy and this is not thread-safe). Its value may be set to values defined in standard header "errno.h".
errno is a library-provided global variable that strtol (as well as other library functions) uses to indicate error conditions. In the above code strtol could change errno after the user set it to 0. ERANGE is indeed a named constant provided by the standard library, which stands for some special value used by strtol to indicate out-of-range errors.
Your char const *s question is too vague. What specifically do you not understand in it? The const part means that the user code inside str2int will not be allowed to modify the string pointed by s. The compiler will do its best to prevent any modifying (or potentially modifying) operations on string pointed by s.

c++ isalnum endless loop

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().