I am making a calculator using command line arguments, and one of the problems I am having is that I can't find a way to display an error to inputs that have more than one ".". 3.33 can be accepted, but 3.3.3.2 cannot because its an invalid number.
int main(int argc, char* argv[]) {
if (argc == 1) {
cout << "E\n";
return 0;
}
if (argc <= 2) {
cout << "P\n";
return 0;
}
if (argc > 4) {
cout << "P\n";
return 0;
}
if (argc == 3) {
cout << endl << (atof(argv[1]) atof(argv[2])) << endl;
return 0;
}
else if (argc == 4)
{
//Addition operation
if (argv[3][0] == 'a')
cout << endl << (atoi(argv[1]) atoi(argv[2])) << endl;
//Subtraction operation
else if (argv[3][0] == 's')
cout << endl << (atof(argv[1]) - atof(argv[2])) << endl;
//Multiplication operation
else if (argv[3][0] == 'm')
cout << endl << (atof(argv[1]) * atof(argv[2])) << endl;
//Division operation
else if (argv[3][0] == 'd')
if (argv[2][0] == '0') {
cout << endl << "error";
return 0;
}
else {
cout << endl << (atof(argv[1]) / atof(argv[2])) << endl;
}
//Exponential operation
else if (argv[3][0] == 'p')
if (argv[2][0] > - 1.00 && argv[2][0] < 1.00) {
cout << endl << "Y";
return 0;
}
else if (argv[1][0] == '-') {
cout << endl << "Y";
return 0;
}
else
cout << endl << pow(atof(argv[1]), atof(argv[2])) << endl;
else
cout << endl << "V" << endl;
//Any other operator
}
}
CodePudding user response:
atof
will stop when it finds characters that cannot be part of the floating point number, and this includes an extra '.'. Unfortunately it does not tell you this happened.
Smarter conversion functions like std::stof
or strtof
will notify you if the entire string was not consumed when parsing.
Example:
size_t end;
float val = std::stof(argv[1], &end);
if (end != strlen(argv[1]))
{
cout << "Bad input: " << argv[1] << "\n";
return -1;
}
will return from main
and exit the program if the entire argument is not consumed when parsing or throw an exception if the number was out of range or no number could be parsed, ending the program if uncaught.
char * endp;
errno = 0;
float val = strtof(argv[1], &endp);
if (*endp != '\0' || errno = ERANGE)
{
cout << "Bad input: " << argv[1] << "\n";
return -1;
}
will return from main
and exit the program if the entire argument is not consumed when parsing or the number was out of range. I personally prefer this option because I don't like throwing exceptions over user input. Users getting the input wrong is not exceptional enough to be worth an exception.
If your compiler is up to date, std::from_chars
can be extremely helpful. The linked documentation provides excellent examples of its usage.
CodePudding user response:
One way for checking the validity of a string is to use regular expressions, for example, you can use this.
You can write something like this to extract your operands:
float op1, op2;
std::string p1 = argv[1];
std::string p2 = argv[2];
std::regex pattern("[ -]?([0-9]*[.])?[0-9] ");
if (std::regex_match(p1, pattern) &&
std::regex_match(p2, pattern)) {
op1 = atof(argv[1]);
op2 = atof(argv[2]);
// ...
} else {
cout << "Error!" << std::endl;
}
Alternatively, you could use the return value of atof to check if an error happened:
Return value
Floating point value corresponding to the contents of str on success. If the converted value falls out of range of corresponding return type, range error occurs and HUGE_VAL, HUGE_VALF or HUGE_VALL is returned. If no conversion can be performed, 0 is returned and *str_end is set to str.